/* =========================================================================== Wolfenstein: Enemy Territory GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Wolfenstein: Enemy Territory GPL Source Code (“Wolf ET Source Code”). Wolf ET 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 3 of the License, or (at your option) any later version. Wolf ET 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 Wolf ET Source Code. If not, see . In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ //=========================================================================== // // Name: g_script_actions.c // Function: Wolfenstein Entity Scripting // Programmer: Ridah // Tab Size: 4 (real tabs) //=========================================================================== #include "../game/g_local.h" #include "../game/q_shared.h" /* Contains the code to handle the various commands available with an event script. These functions will return true if the action has been performed, and the script should proceed to the next item on the list. */ void script_linkentity( gentity_t *ent ); int G_RemoveNamedBot( char *name ); qboolean G_ScriptAction_SetModelFromBrushmodel( gentity_t *ent, char *params ) { char *pString, *token; char modelname[MAX_QPATH]; int i; qboolean solid = qtrue; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setmodelfrombrushmodel must have an targetname\n" ); } Q_strncpyz( modelname, token, MAX_QPATH ); ent->r.svFlags &= ~SVF_IGNOREBMODELEXTENTS; while ( *token ) { if ( !Q_stricmp( token, "useoriginforpvs" ) ) { ent->r.svFlags |= SVF_IGNOREBMODELEXTENTS; } else if ( !Q_stricmp( token, "nonsolid" ) ) { solid = qfalse; } token = COM_ParseExt( &pString, qfalse ); } for ( i = 0; i < level.numBrushModels; i++ ) { if ( !Q_stricmp( level.brushModelInfo[i].modelname, modelname ) ) { trap_SetBrushModel( ent, va( "*%i", level.brushModelInfo[i].model ) ); if ( !solid ) { ent->s.eFlags |= EF_NONSOLID_BMODEL; ent->clipmask = 0; ent->r.contents = 0; trap_LinkEntity( ent ); } return qtrue; } } G_Error( "G_Scripting: setmodelfrombrushmodel target not found %s\n", modelname ); return qtrue; } qboolean G_ScriptAction_SetPosition( gentity_t *ent, char *params ) { pathCorner_t* pPathCorner; char *pString, *token; gentity_t *target; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setposition must have an targetname\n" ); } if ( ( pPathCorner = BG_Find_PathCorner( token ) ) ) { G_SetOrigin( ent, pPathCorner->origin ); } else { // find the entity with the given "targetname" target = G_FindByTargetname( NULL, token ); if ( !target ) { G_Error( "G_Scripting: can't find entity with \"targetname\" = \"%s\"\n", token ); } G_SetOrigin( ent, target->r.currentOrigin ); if ( ent->client ) { VectorCopy( target->r.currentOrigin, ent->client->ps.origin ); } } return qtrue; } void SetPlayerSpawn( gentity_t* ent, int spawn, qboolean update ); qboolean G_ScriptAction_SetAutoSpawn( gentity_t* ent, char *params ) { char *pString, *token; char spawnname[MAX_QPATH]; team_t team; int* pTeamAutoSpawn; gentity_t* tent; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setautospawn must have a target spawn\n" ); } Q_strncpyz( spawnname, token, MAX_QPATH ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setautospawn must have a target team\n" ); } team = atoi( token ); pTeamAutoSpawn = team == 0 ? &( level.axisAutoSpawn ) : &( level.alliesAutoSpawn ); tent = G_Find( NULL, FOFS( message ), spawnname ); if ( !tent ) { G_Error( "G_Scripting: setautospawn, couldn't find target\n" ); } if ( !tent->count ) { return qfalse; } G_Printf( "Setting %s autospawn to %s\n", team == 0 ? "Axis" : "Allied", spawnname ); *pTeamAutoSpawn = tent->count - CS_MULTI_SPAWNTARGETS; G_UpdateSpawnCounts(); return qtrue; } qboolean G_ScriptAction_ChangeModel( gentity_t* ent, char *params ) { char *pString, *token; char tagname[MAX_QPATH]; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: changemodel must have a target model name\n" ); } COM_StripExtension( token, tagname ); Q_strcat( tagname, MAX_QPATH, ".tag" ); ent->tagNumber = trap_LoadTag( tagname ); ent->s.modelindex2 = G_ModelIndex( token ); return qtrue; } qboolean G_ScriptAction_ShaderRemap( gentity_t* ent, char *params ) { char *pString, *token; float f = level.time * 0.001; char oldShader[256]; char newShader[256]; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: remapshader must have a target shader name\n" ); } Q_strncpyz( oldShader, token, 256 ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: remapshader must have a new shader name\n" ); } Q_strncpyz( newShader, token, 256 ); AddRemap( oldShader, newShader, f ); // trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig()); return qtrue; } qboolean G_ScriptAction_ShaderRemapFlush( gentity_t* ent, char *params ) { trap_SetConfigstring( CS_SHADERSTATE, BuildShaderStateConfig() ); return qtrue; } qboolean G_ScriptAction_FollowPath( gentity_t* ent, char *params ) { char *pString, *token; float speed; qboolean wait = qfalse; int backward; float length = 0; float dist; int i; if ( params && ( ent->scriptStatus.scriptFlags & SCFL_GOING_TO_MARKER ) ) { // we can't process a new movement until the last one has finished return qfalse; } if ( !params || ent->scriptStatus.scriptStackChangeTime < level.time ) { // we are waiting for it to reach destination if ( ent->s.pos.trTime + ent->s.pos.trDuration <= level.time ) { // we made it ent->scriptStatus.scriptFlags &= ~SCFL_GOING_TO_MARKER; // set the angles at the destination BG_EvaluateTrajectory( &ent->s.apos, ent->s.apos.trTime + ent->s.apos.trDuration, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); // stop moving BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin, qfalse, ent->s.effect2Time ); VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); ent->s.pos.trTime = level.time; ent->s.pos.trDuration = 0; ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); script_linkentity( ent ); return qtrue; } } else { // we have just started this command splinePath_t* pSpline; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followpath must have a direction\n" ); } backward = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followpath must have an targetname\n" ); } if ( !( pSpline = BG_Find_Spline( token ) ) ) { G_Error( "G_Scripting: can't find spline with \"targetname\" = \"%s\"\n", token ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followpath must have a speed\n" ); } speed = atof( token ); while ( token[0] ) { token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { if ( !Q_stricmp( token, "wait" ) ) { wait = qtrue; } if ( !Q_stricmp( token, "length" ) ) { token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: length must have a value\n" ); } length = atoi( token ); } } } // calculate the trajectory ent->s.apos.trType = ent->s.pos.trType = TR_LINEAR_PATH; ent->s.apos.trTime = ent->s.pos.trTime = level.time; ent->s.apos.trBase[0] = length; ent->s.effect2Time = backward ? -( pSpline - splinePaths + 1 ) : pSpline - splinePaths + 1; VectorClear( ent->s.pos.trDelta ); dist = 0; for ( i = 0; i < MAX_SPLINE_SEGMENTS; i++ ) { dist += pSpline->segments[i].length; } ent->s.apos.trDuration = ent->s.pos.trDuration = 1000 * ( dist / speed ); if ( !wait ) { // round the duration to the next 50ms if ( ent->s.pos.trDuration % 50 ) { float frac; frac = (float)( ( ( ent->s.pos.trDuration / 50 ) * 50 + 50 ) - ent->s.pos.trDuration ) / (float)( ent->s.pos.trDuration ); if ( frac < 1 ) { ent->s.apos.trDuration = ent->s.pos.trDuration = ( ent->s.pos.trDuration / 50 ) * 50 + 50; } } // set the goto flag, so we can keep processing the move until we reach the destination ent->scriptStatus.scriptFlags |= SCFL_GOING_TO_MARKER; return qtrue; // continue to next command } } BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin, qfalse, ent->s.effect2Time ); BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); script_linkentity( ent ); return qfalse; } qboolean G_ScriptAction_AttatchToTrain( gentity_t* ent, char *params ) { char* pString; char* token; gentity_t* target; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: attatchtotrain must have a target\n" ); } target = G_FindByTargetname( NULL, token ); if ( !target ) { G_Error( "G_Scripting: can't find entity with \"targetname\" = \"%s\"\n", token ); } ent->s.torsoAnim = target->s.number; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: attatchtotrain must have a length\n" ); } ent->s.angles2[0] = atoi( token ); ent->s.eFlags |= EF_PATH_LINK; return qtrue; } qboolean G_ScriptAction_FreezeAnimation( gentity_t* ent, char *params ) { ent->s.loopSound = 1; return qtrue; } qboolean G_ScriptAction_UnFreezeAnimation( gentity_t* ent, char *params ) { ent->s.loopSound = 0; return qtrue; } qboolean G_ScriptAction_StartAnimation( gentity_t* ent, char *params ) { char* pString; char* token; qboolean norandom = qfalse; qboolean nolerp = qfalse; qboolean noloop = qfalse; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: startanimation must have a start frame\n" ); } ent->s.legsAnim = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: startanimation must have a frame count\n" ); } ent->s.torsoAnim = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: startanimation must have an fps count\n" ); } ent->s.weapon = 1000.f / atoi( token ); while ( token[0] ) { token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { if ( !Q_stricmp( token, "norandom" ) ) { norandom = qtrue; } if ( !Q_stricmp( token, "nolerp" ) ) { nolerp = qtrue; } if ( !Q_stricmp( token, "noloop" ) ) { noloop = qtrue; } } } if ( norandom ) { ent->s.frame = 0; } else { ent->s.frame = rand() % ent->s.torsoAnim; } if ( noloop ) { ent->s.clientNum = 1; } else { ent->s.clientNum = 0; } if ( nolerp ) { ent->s.animMovetype++; } return qtrue; } qboolean G_ScriptAction_SetSpeed( gentity_t* ent, char *params ) { vec3_t speed; char* pString; int i; char* token; qboolean gravity = qfalse; qboolean lowgravity = qfalse; BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin, qtrue, ent->s.effect2Time ); VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); pString = params; for ( i = 0; i < 3; i++ ) { token = COM_Parse( &pString ); if ( !token || !*token ) { G_Error( "G_Scripting: syntax: setspeed [gravity|lowgravity]\n" ); } speed[i] = atoi( token ); } while ( ( token = COM_Parse( &pString ) ) && *token ) { if ( !Q_stricmp( token, "gravity" ) ) { gravity = qtrue; } else if ( !Q_stricmp( token, "lowgravity" ) ) { lowgravity = qtrue; } } if ( gravity ) { ent->s.pos.trType = TR_GRAVITY; } else if ( lowgravity ) { ent->s.pos.trType = TR_GRAVITY_LOW; } else { ent->s.pos.trType = TR_LINEAR; } ent->s.pos.trTime = level.time; VectorCopy( speed, ent->s.pos.trDelta ); script_linkentity( ent ); return qtrue; } qboolean G_ScriptAction_SetRotation( gentity_t* ent, char *params ) { vec3_t angles; char* pString; int i; char* token; BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); VectorCopy( ent->r.currentAngles, ent->s.apos.trBase ); ent->s.apos.trType = TR_LINEAR; ent->s.apos.trTime = level.time; pString = params; for ( i = 0; i < 3; i++ ) { token = COM_Parse( &pString ); if ( !token || !token[0] ) { G_Error( "G_Scripting: syntax: setrotation \n" ); } angles[i] = atoi( token ); } VectorCopy( angles, ent->s.apos.trDelta ); script_linkentity( ent ); return qtrue; } qboolean G_ScriptAction_StopRotation( gentity_t* ent, char *params ) { BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); VectorCopy( ent->r.currentAngles, ent->s.apos.trBase ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); return qtrue; } /* =============== G_ScriptAction_FollowSpline syntax: followspline [wait] NOTE: speed may be modified to round the duration to the next 50ms for smooth transitions =============== */ qboolean G_ScriptAction_FollowSpline( gentity_t* ent, char *params ) { char *pString, *token; vec3_t vec; float speed; qboolean wait = qfalse; int backward; float length = 0; float roll[2] = { 0, 0 }; if ( params && ( ent->scriptStatus.scriptFlags & SCFL_GOING_TO_MARKER ) ) { // we can't process a new movement until the last one has finished return qfalse; } if ( !params || ent->scriptStatus.scriptStackChangeTime < level.time ) { // we are waiting for it to reach destination if ( ent->s.pos.trTime + ent->s.pos.trDuration <= level.time ) { // we made it ent->scriptStatus.scriptFlags &= ~SCFL_GOING_TO_MARKER; // set the angles at the destination BG_EvaluateTrajectory( &ent->s.apos, ent->s.apos.trTime + ent->s.apos.trDuration, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); // stop moving BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin, qfalse, ent->s.effect2Time ); VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); ent->s.pos.trTime = level.time; ent->s.pos.trDuration = 0; ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); script_linkentity( ent ); return qtrue; } } else { // we have just started this command splinePath_t* pSpline; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followspline must have a direction\n" ); } if ( !Q_stricmp( token, "accum" ) ) { int bufferIndex; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a buffer index\n" ); } bufferIndex = atoi( token ); if ( bufferIndex < 0 || bufferIndex >= G_MAX_SCRIPT_ACCUM_BUFFERS ) { G_Error( "G_Scripting: accum buffer is outside range (0 - %i)\n", G_MAX_SCRIPT_ACCUM_BUFFERS - 1 ); } backward = ent->scriptAccumBuffer[bufferIndex] != 0 ? qtrue : qfalse; } else if ( !Q_stricmp( token, "globalaccum" ) ) { int bufferIndex; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a buffer index\n" ); } bufferIndex = atoi( token ); if ( bufferIndex < 0 || bufferIndex >= G_MAX_SCRIPT_ACCUM_BUFFERS ) { G_Error( "G_Scripting: accum buffer is outside range (0 - %i)\n", G_MAX_SCRIPT_ACCUM_BUFFERS - 1 ); } backward = level.globalAccumBuffer[bufferIndex] != 0 ? qtrue : qfalse; } else { backward = atoi( token ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followspline must have an targetname\n" ); } if ( !( pSpline = BG_Find_Spline( token ) ) ) { G_Error( "G_Scripting: can't find spline with \"targetname\" = \"%s\"\n", token ); } VectorSubtract( pSpline->point.origin, ent->r.currentOrigin, vec ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: followspline must have a speed\n" ); } speed = atof( token ); while ( token[0] ) { token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { if ( !Q_stricmp( token, "wait" ) ) { wait = qtrue; } if ( !Q_stricmp( token, "length" ) ) { token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: length must have a value\n" ); } length = atoi( token ); } if ( !Q_stricmp( token, "roll" ) ) { token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: roll must have a start angle\n" ); } roll[0] = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: roll must have an end angle\n" ); } roll[1] = atoi( token ); } if ( !Q_stricmp( token, "dampin" ) ) { if ( roll[0] >= 0 ) { roll[0] += 1000; } else { roll[0] -= 1000; } } if ( !Q_stricmp( token, "dampout" ) ) { if ( roll[0] >= 0 ) { roll[0] += 10000; } else { roll[0] -= 10000; } } } } // calculate the trajectory ent->s.apos.trType = ent->s.pos.trType = TR_SPLINE; ent->s.apos.trTime = ent->s.pos.trTime = level.time; ent->s.apos.trBase[0] = length; ent->s.apos.trBase[1] = roll[0]; ent->s.apos.trBase[2] = roll[1]; ent->s.effect2Time = backward ? -( pSpline - splinePaths + 1 ) : pSpline - splinePaths + 1; VectorClear( ent->s.pos.trDelta ); ent->s.apos.trDuration = ent->s.pos.trDuration = 1000 * ( pSpline->length / speed ); if ( !wait ) { // round the duration to the next 50ms if ( ent->s.pos.trDuration % 50 ) { float frac; frac = (float)( ( ( ent->s.pos.trDuration / 50 ) * 50 + 50 ) - ent->s.pos.trDuration ) / (float)( ent->s.pos.trDuration ); if ( frac < 1 ) { ent->s.apos.trDuration = ent->s.pos.trDuration = ( ent->s.pos.trDuration / 50 ) * 50 + 50; } } // set the goto flag, so we can keep processing the move until we reach the destination ent->scriptStatus.scriptFlags |= SCFL_GOING_TO_MARKER; return qtrue; // continue to next command } } BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin, qfalse, ent->s.effect2Time ); BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); script_linkentity( ent ); return qfalse; } /* =============== G_ScriptAction_AbortMove syntax: abortmove =============== */ qboolean G_ScriptAction_AbortMove( gentity_t *ent, char *params ) { ent->scriptStatus.scriptFlags &= ~SCFL_GOING_TO_MARKER; // set the angles at the destination BG_EvaluateTrajectory( &ent->s.apos, ent->s.apos.trTime + ent->s.apos.trDuration, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); // stop moving BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin, qfalse, ent->s.effect2Time ); VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); ent->s.pos.trTime = level.time; ent->s.pos.trDuration = 0; ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); script_linkentity( ent ); return qtrue; } /* =============== G_ScriptAction_SetChargeTimeFactor syntax: setchargetimefactor team: 0 = axis, 1 = allies =============== */ qboolean G_ScriptAction_SetChargeTimeFactor( gentity_t* ent, char *params ) { char *pString, *token; float factor; team_t team; char playerclass[64]; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setchargetimefactor must have a team\n" ); } team = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setchargetimefactor must have a class name\n" ); } Q_strncpyz( playerclass, token, sizeof( playerclass ) ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setchargetimefactor must have a factor\n" ); } factor = atof( token ); if ( factor < 0.f ) { G_Printf( "^3WARNING: setchargetimefactor with factor < 0, clamped to 0\n" ); factor = 0; } else if ( factor > 1.f ) { G_Printf( "^3WARNING: setchargetimefactor with factor > 1, clamped to 1\n" ); factor = 1.f; } if ( !Q_stricmp( playerclass, "soldier" ) ) { level.soldierChargeTimeModifier[team] = factor; level.soldierChargeTime[team] = g_soldierChargeTime.integer * factor; } else if ( !Q_stricmp( playerclass, "medic" ) ) { level.medicChargeTimeModifier[team] = factor; level.medicChargeTime[team] = g_medicChargeTime.integer * factor; } else if ( !Q_stricmp( playerclass, "engineer" ) ) { level.engineerChargeTimeModifier[team] = factor; level.engineerChargeTime[team] = g_engineerChargeTime.integer * factor; } else if ( !Q_stricmp( playerclass, "fieldops" ) ) { level.lieutenantChargeTimeModifier[team] = factor; level.lieutenantChargeTime[team] = g_LTChargeTime.integer * factor; } else if ( !Q_stricmp( playerclass, "lieutenant" ) ) { // FIXME: remove from missionpack level.lieutenantChargeTimeModifier[team] = factor; level.lieutenantChargeTime[team] = g_LTChargeTime.integer * factor; } else if ( !Q_stricmp( playerclass, "covertops" ) ) { level.covertopsChargeTimeModifier[team] = factor; level.covertopsChargeTime[team] = g_covertopsChargeTime.integer * factor; } { char cs[MAX_INFO_STRING]; cs[0] = '\0'; Info_SetValueForKey( cs, "axs_sld", va( "%i", level.soldierChargeTime[0] ) ); Info_SetValueForKey( cs, "ald_sld", va( "%i", level.soldierChargeTime[1] ) ); Info_SetValueForKey( cs, "axs_mdc", va( "%i", level.medicChargeTime[0] ) ); Info_SetValueForKey( cs, "ald_mdc", va( "%i", level.medicChargeTime[1] ) ); Info_SetValueForKey( cs, "axs_eng", va( "%i", level.engineerChargeTime[0] ) ); Info_SetValueForKey( cs, "ald_eng", va( "%i", level.engineerChargeTime[1] ) ); Info_SetValueForKey( cs, "axs_lnt", va( "%i", level.lieutenantChargeTime[0] ) ); Info_SetValueForKey( cs, "ald_lnt", va( "%i", level.lieutenantChargeTime[1] ) ); Info_SetValueForKey( cs, "axs_cvo", va( "%i", level.covertopsChargeTime[0] ) ); Info_SetValueForKey( cs, "ald_cvo", va( "%i", level.covertopsChargeTime[1] ) ); trap_SetConfigstring( CS_CHARGETIMES, cs ); } return qtrue; } // Gordon: debris test /* ================= G_ScriptAction_SpawnRubble syntax: spawnrubble ================= */ qboolean G_ScriptAction_SpawnRubble( gentity_t *ent, char *params ) { int i; for ( i = 0; i < MAX_DEBRISCHUNKS; i++ ) { if ( !Q_stricmp( level.debrisChunks[i].targetname, params ) ) { gentity_t* temp = G_TempEntity( level.debrisChunks[i].origin, EV_DEBRIS ); VectorCopy( level.debrisChunks[i].velocity, temp->s.origin2 ); temp->s.modelindex = level.debrisChunks[i].model; } } return qtrue; } /* ================= G_ScriptAction_AllowTankExit syntax: allowtankexit ================= */ qboolean G_ScriptAction_AllowTankExit( gentity_t *ent, char *params ) { char *pString, *token; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: allowtankexit must have a enable value\n" ); } if ( !Q_stricmp( token, "yes" ) || !Q_stricmp( token, "on" ) || atoi( token ) ) { level.disableTankExit = qfalse; } else { level.disableTankExit = qtrue; } return qtrue; } qboolean G_ScriptAction_AllowTankEnter( gentity_t *ent, char *params ) { char *pString, *token; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: allowtankenter must have a enable value\n" ); } if ( !Q_stricmp( token, "yes" ) || !Q_stricmp( token, "on" ) || atoi( token ) ) { level.disableTankEnter = qfalse; } else { level.disableTankEnter = qtrue; } return qtrue; } qboolean G_ScriptAction_SetTankAmmo( gentity_t *ent, char *params ) { char *pString, *token; gentity_t* tank; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: settankammo must have a target\n" ); } tank = G_FindByTargetname( NULL, token ); if ( !tank ) { G_Error( "G_Scripting: settankammo, failed to find target (%s)\n", token ); } if ( tank->s.eType != ET_MOVER ) { G_Error( "G_Scripting: settankammo, must target a mover\n" ); } token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: settankammo must have an amount\n" ); } tank->s.effect1Time = atoi( token ); return qtrue; } qboolean G_ScriptAction_AddTankAmmo( gentity_t *ent, char *params ) { char *pString, *token; gentity_t* tank; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: addtankammo must have a target\n" ); } tank = G_FindByTargetname( NULL, token ); if ( !tank ) { G_Error( "G_Scripting: addtankammo, failed to find target (%s)\n", token ); } if ( tank->s.eType != ET_MOVER ) { G_Error( "G_Scripting: addtankammo, must target a mover\n" ); } token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: addtankammo must have an amount\n" ); } tank->s.effect1Time += atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( *token ) { if ( tank->s.effect1Time > atoi( token ) ) { tank->s.effect1Time = atoi( token ); } } return qtrue; } qboolean G_ScriptAction_DisableMessage( gentity_t *ent, char *params ) { char *pString, *token; gentity_t* target = NULL; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setposition must have an targetname\n" ); } // find the entity with the given "targetname" while ( ( target = G_FindByTargetname( target, token ) ) ) { target->s.aiState = 1; } return qtrue; } /* ================= G_ScriptAction_Kill ================= */ qboolean G_ScriptAction_Kill( gentity_t *ent, char *params ) { char *pString, *token; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: kill must have a target\n" ); } G_KillEnts( token, NULL, ent->enemy, ent->deathType ); return qtrue; } /* ================= G_ScriptAction_SetGlobalFog syntax: setglobalfog [float:r] [float:g] [float:b] [float:depthForOpaque] ================= */ qboolean G_ScriptAction_SetGlobalFog( gentity_t *ent, char *params ) { char *pString, *token; qboolean restore; int duration; vec3_t color; float depthForOpaque; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setglobalfog must have a restore value\n" ); } restore = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setglobalfog must have a duration value\n" ); } duration = atoi( token ); if ( restore ) { trap_SetConfigstring( CS_GLOBALFOGVARS, va( "1 %i 0 0 0 0", duration ) ); return qtrue; } Parse1DMatrix( &pString, 3, color ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: setglobalfog without restore flag must have a depth for opaque value\n" ); } depthForOpaque = atof( token ); trap_SetConfigstring( CS_GLOBALFOGVARS, va( "0 %i %f %f %f %f", duration, color[0], color[1], color[2], depthForOpaque ) ); return qtrue; } // =================== /* =============== G_ScriptAction_GotoMarker syntax: gotomarker [accel/deccel] [turntotarget] [wait] [relative ] NOTE: speed may be modified to round the duration to the next 50ms for smooth transitions =============== */ qboolean G_ScriptAction_GotoMarker( gentity_t *ent, char *params ) { char *pString, *token; gentity_t *target = NULL; vec3_t vec; float speed, dist; qboolean wait = qfalse, turntotarget = qfalse; int trType; int duration, i; vec3_t diff; vec3_t angles; if ( params && ( ent->scriptStatus.scriptFlags & SCFL_GOING_TO_MARKER ) ) { // we can't process a new movement until the last one has finished return qfalse; } if ( !params || ent->scriptStatus.scriptStackChangeTime < level.time ) { // we are waiting for it to reach destination if ( ent->s.pos.trTime + ent->s.pos.trDuration <= level.time ) { // we made it ent->scriptStatus.scriptFlags &= ~SCFL_GOING_TO_MARKER; // set the angles at the destination BG_EvaluateTrajectory( &ent->s.apos, ent->s.apos.trTime + ent->s.apos.trDuration, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); // stop moving BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin, qfalse, ent->s.effect2Time ); VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); ent->s.pos.trTime = level.time; ent->s.pos.trDuration = 0; ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); script_linkentity( ent ); return qtrue; } } else { // we have just started this command pathCorner_t* pPathCorner; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: gotomarker must have an targetname\n" ); } if ( ( pPathCorner = BG_Find_PathCorner( token ) ) ) { VectorSubtract( pPathCorner->origin, ent->r.currentOrigin, vec ); } else { // find the entity with the given "targetname" target = G_FindByTargetname( NULL, token ); if ( !target ) { G_Error( "G_Scripting: can't find entity with \"targetname\" = \"%s\"\n", token ); } VectorSubtract( target->r.currentOrigin, ent->r.currentOrigin, vec ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: gotomarker must have a speed\n" ); } speed = atof( token ); trType = TR_LINEAR_STOP; while ( token[0] ) { token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { if ( !Q_stricmp( token, "accel" ) ) { trType = TR_ACCELERATE; } else if ( !Q_stricmp( token, "deccel" ) ) { trType = TR_DECCELERATE; } else if ( !Q_stricmp( token, "wait" ) ) { wait = qtrue; } else if ( !Q_stricmp( token, "turntotarget" ) ) { turntotarget = qtrue; } else if ( !Q_stricmp( token, "relative" ) ) { gentity_t* target2; pathCorner_t* pPathCorner2; vec3_t vec2; token = COM_ParseExt( &pString, qfalse ); if ( ( pPathCorner2 = BG_Find_PathCorner( token ) ) ) { VectorCopy( pPathCorner2->origin, vec2 ); } else if ( ( target2 = G_FindByTargetname( NULL, token ) ) ) { VectorCopy( target2->r.currentOrigin, vec2 ); } else { G_Error( "Target for relative gotomarker not found: %s\n", token ); } VectorAdd( vec, ent->r.currentOrigin, vec ); VectorSubtract( vec, vec2, vec ); } } } // start the movement if ( ent->s.eType == ET_MOVER ) { VectorCopy( vec, ent->movedir ); VectorCopy( ent->r.currentOrigin, ent->pos1 ); VectorAdd( ent->r.currentOrigin, vec, ent->pos2 ); ent->speed = speed; dist = VectorDistance( ent->pos1, ent->pos2 ); // setup the movement with the new parameters InitMover( ent ); if ( ent->s.eType == ET_MOVER && ent->spawnflags & 8 ) { ent->use = script_mover_use; } // start the movement SetMoverState( ent, MOVER_1TO2, level.time ); if ( trType != TR_LINEAR_STOP ) { // allow for acceleration/decceleration ent->s.pos.trDuration = 1000.0 * dist / ( speed / 2.0 ); ent->s.pos.trType = trType; } ent->reached = NULL; if ( turntotarget && !pPathCorner ) { duration = ent->s.pos.trDuration; VectorCopy( target->s.angles, angles ); for ( i = 0; i < 3; i++ ) { diff[i] = AngleDifference( angles[i], ent->s.angles[i] ); while ( diff[i] > 180 ) diff[i] -= 360; while ( diff[i] < -180 ) diff[i] += 360; } VectorCopy( ent->s.angles, ent->s.apos.trBase ); if ( duration ) { VectorScale( diff, 1000.0 / (float)duration, ent->s.apos.trDelta ); } else { VectorClear( ent->s.apos.trDelta ); } ent->s.apos.trDuration = duration; ent->s.apos.trTime = level.time; ent->s.apos.trType = TR_LINEAR_STOP; if ( trType != TR_LINEAR_STOP ) { // allow for acceleration/decceleration ent->s.pos.trDuration = 1000.0 * dist / ( speed / 2.0 ); ent->s.pos.trType = trType; } } } else { // calculate the trajectory ent->s.pos.trType = TR_LINEAR_STOP; ent->s.pos.trTime = level.time; VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); dist = VectorNormalize( vec ); VectorScale( vec, speed, ent->s.pos.trDelta ); ent->s.pos.trDuration = 1000 * ( dist / speed ); if ( turntotarget && !pPathCorner ) { duration = ent->s.pos.trDuration; VectorCopy( target->s.angles, angles ); for ( i = 0; i < 3; i++ ) { diff[i] = AngleDifference( angles[i], ent->s.angles[i] ); while ( diff[i] > 180 ) diff[i] -= 360; while ( diff[i] < -180 ) diff[i] += 360; } VectorCopy( ent->s.angles, ent->s.apos.trBase ); if ( duration ) { VectorScale( diff, 1000.0 / (float)duration, ent->s.apos.trDelta ); } else { VectorClear( ent->s.apos.trDelta ); } ent->s.apos.trDuration = duration; ent->s.apos.trTime = level.time; ent->s.apos.trType = TR_LINEAR_STOP; } } if ( !wait ) { // round the duration to the next 50ms if ( ent->s.pos.trDuration % 50 ) { float frac; frac = (float)( ( ( ent->s.pos.trDuration / 50 ) * 50 + 50 ) - ent->s.pos.trDuration ) / (float)( ent->s.pos.trDuration ); if ( frac < 1 ) { VectorScale( ent->s.pos.trDelta, 1.0 / ( 1.0 + frac ), ent->s.pos.trDelta ); ent->s.pos.trDuration = ( ent->s.pos.trDuration / 50 ) * 50 + 50; } } // set the goto flag, so we can keep processing the move until we reach the destination ent->scriptStatus.scriptFlags |= SCFL_GOING_TO_MARKER; return qtrue; // continue to next command } } BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->r.currentOrigin, qfalse, ent->s.effect2Time ); BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); script_linkentity( ent ); return qfalse; } /* ================= G_ScriptAction_Wait syntax: wait wait random ================= */ qboolean G_ScriptAction_Wait( gentity_t *ent, char *params ) { char *pString, *token; int duration; // get the duration pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: wait must have a duration\n" ); } // Gordon: adding random wait ability if ( !Q_stricmp( token, "random" ) ) { int min, max; token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: wait random must have a min duration\n" ); } min = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !*token ) { G_Error( "G_Scripting: wait random must have a max duration\n" ); } max = atoi( token ); if ( ent->scriptStatus.scriptStackChangeTime + min > level.time ) { return qfalse; } if ( ent->scriptStatus.scriptStackChangeTime + max < level.time ) { return qtrue; } return !( rand() % (int)( ( max - min ) * 0.02f ) ); } duration = atoi( token ); return ( ent->scriptStatus.scriptStackChangeTime + duration < level.time ); } /* ================= G_ScriptAction_Trigger syntax: trigger Calls the specified trigger for the given ai character or script entity ================= */ qboolean G_ScriptAction_Trigger( gentity_t *ent, char *params ) { gentity_t *trent; char *pString, name[MAX_QPATH], trigger[MAX_QPATH], *token; int oldId, i; qboolean terminate, found; // get the cast name pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( trigger, token, sizeof( trigger ) ); if ( !*trigger ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } if ( !Q_stricmp( name, "self" ) ) { trent = ent; oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", trigger ); // if the script changed, return false so we don't muck with it's variables return ( ( trent != ent ) || ( oldId == trent->scriptStatus.scriptId ) ); } else if ( !Q_stricmp( name, "global" ) ) { terminate = qfalse; found = qfalse; // for all entities/bots with this scriptName trent = g_entities; for ( i = 0; i < level.num_entities; i++, trent++ ) { if ( !trent->inuse ) { continue; } if ( !trent->scriptName ) { continue; } if ( !trent->scriptName[0] ) { continue; } found = qtrue; if ( !( trent->r.svFlags & SVF_BOT ) ) { oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", trigger ); // if the script changed, return false so we don't muck with it's variables if ( ( trent == ent ) && ( oldId != trent->scriptStatus.scriptId ) ) { terminate = qtrue; } } else { Bot_ScriptEvent( trent->s.number, "trigger", trigger ); } } // if ( terminate ) { return qfalse; } if ( found ) { return qtrue; } } else if ( !Q_stricmp( name, "player" ) ) { for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( level.clients[i].pers.connected != CON_CONNECTED ) { continue; } G_Script_ScriptEvent( &g_entities[i], "trigger", trigger ); } return qtrue; // always true, as players aren't always there } else if ( !Q_stricmp( name, "activator" ) ) { if ( ent->activator && ent->activator->client && ( ent->activator->r.svFlags & SVF_BOT ) && ent->inuse && ent->activator->client->ps.stats[STAT_HEALTH] > 0 ) { Bot_ScriptEvent( ent->activator - g_entities, "trigger", trigger ); } return qtrue; // always true, as players aren't always there } else { terminate = qfalse; found = qfalse; // for all entities/bots with this scriptName trent = NULL; while ( ( trent = G_Find( trent, FOFS( scriptName ), name ) ) ) { found = qtrue; if ( !( trent->r.svFlags & SVF_BOT ) ) { oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", trigger ); // if the script changed, return false so we don't muck with it's variables if ( ( trent == ent ) && ( oldId != trent->scriptStatus.scriptId ) ) { terminate = qtrue; } } else { Bot_ScriptEvent( trent->s.number, "trigger", trigger ); } } // if ( terminate ) { return qfalse; } if ( found ) { return qtrue; } } // G_Error( "G_Scripting: trigger has unknown name: %s\n", name ); G_Printf( "G_Scripting: trigger has unknown name: %s\n", name ); return qtrue; // shutup the compiler } /* ================ G_ScriptAction_PlaySound syntax: playsound [LOOPING] Currently only allows playing on the VOICE channel, unless you use a sound script. Use the optional LOOPING paramater to attach the sound to the entities looping channel. ================ */ qboolean G_ScriptAction_PlaySound( gentity_t *ent, char *params ) { char *pString, *token; char sound[MAX_QPATH]; qboolean looping = qfalse; int volume = 255; if ( !params ) { G_Error( "G_Scripting: syntax error\n\nplaysound \n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( sound, token, sizeof( sound ) ); token = COM_ParseExt( &pString, qfalse ); while ( *token ) { if ( !Q_stricmp( token, "looping" ) ) { looping = qtrue; } else if ( !Q_stricmp( token, "volume" ) ) { token = COM_ParseExt( &pString, qfalse ); volume = atoi( token ); if ( !volume ) { volume = 255; } } token = COM_ParseExt( &pString, qfalse ); } if ( !looping ) { if ( volume == 255 ) { G_AddEvent( ent, EV_GENERAL_SOUND, G_SoundIndex( sound ) ); } else { G_AddEvent( ent, EV_GENERAL_SOUND_VOLUME, G_SoundIndex( sound ) ); ent->s.onFireStart = volume >> 1; } } else { // looping channel ent->s.loopSound = G_SoundIndex( sound ); ent->s.onFireStart = volume >> 1; } return qtrue; } // START Mad Doc - TDF /* ================ G_ScriptAction_FadeAllSounds syntax: fadeallsounds [UP/DOWN] time Fades all sounds up or down, going from the current level to max or zero in 'time' milliseconds ================ */ qboolean G_ScriptAction_FadeAllSounds( gentity_t *ent, char *params ) { char *pString, *token; qboolean up = qfalse; int time; if ( !params ) { G_Error( "G_Scripting: usage: FadeAllSounds [up|down] time\n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !Q_stricmp( token, "up" ) ) { up = qtrue; } else if ( !Q_stricmp( token, "down" ) ) { up = qfalse; } else { G_Error( "G_Scripting: FadeAllSounds found '%s' when expecting [up|down]\n", token ); } token = COM_ParseExt( &pString, qfalse ); time = atoi( token ); if ( !time ) { G_Error( "G_Scripting: FadeAllSounds found '%s' when expecting 'time'\n", token ); } trap_SendServerCommand( -1, va( "snd_fade %f %d %i", ( up ) ? 1.0 : 0.0, time, ( up ) ? 0 : 1 ) ); return qtrue; } //GS Copied in code from old source for mu_start, mu_play & mu_stop /* ================== AICast_ScriptAction_MusicStart ================== */ qboolean G_ScriptAction_MusicStart( gentity_t *ent, char *params ) { char *pString, *token; char cvarName[MAX_QPATH]; int fadeupTime = 0; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: syntax: mu_start " ); } Q_strncpyz( cvarName, token, sizeof( cvarName ) ); token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { fadeupTime = atoi( token ); } trap_SendServerCommand( -1, va( "mu_start %s %d", cvarName, fadeupTime ) ); return qtrue; } /* ================== AICast_ScriptAction_MusicPlay ================== */ qboolean G_ScriptAction_MusicPlay( gentity_t *ent, char *params ) { char *pString, *token; char cvarName[MAX_QPATH]; int fadeupTime = 0; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: syntax: mu_play [fadeup time]" ); } Q_strncpyz( cvarName, token, sizeof( cvarName ) ); trap_SendServerCommand( -1, va( "mu_play %s %d", cvarName, fadeupTime ) ); return qtrue; } /* ================== AICast_ScriptAction_MusicStop ================== */ qboolean G_ScriptAction_MusicStop( gentity_t *ent, char *params ) { char *pString, *token; int fadeoutTime = 0; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { fadeoutTime = atoi( token ); } trap_SendServerCommand( -1, va( "mu_stop %i\n", fadeoutTime ) ); return qtrue; } /* ================== G_ScriptAction_MusicQueue ================== */ qboolean G_ScriptAction_MusicQueue( gentity_t *ent, char *params ) { char *pString, *token; char cvarName[MAX_QPATH]; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: syntax: mu_queue " ); } Q_strncpyz( cvarName, token, sizeof( cvarName ) ); trap_SetConfigstring( CS_MUSIC_QUEUE, cvarName ); return qtrue; } /* ================== G_ScriptAction_MusicFade ================== */ qboolean G_ScriptAction_MusicFade( gentity_t *ent, char *params ) { char *pString, *token; int fadeoutTime = 0; float targetVol = 0.0; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: syntax: mu_fade " ); } targetVol = atof( token ); if ( targetVol < 0 || targetVol >= 1 ) { G_Error( "G_Scripting: syntax: mu_fade " ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] || token[0] < '0' || token[0] > '9' ) { G_Error( "G_Scripting: syntax: mu_fade " ); } fadeoutTime = atoi( token ); trap_SendServerCommand( -1, va( "mu_fade %f %i\n", targetVol, fadeoutTime ) ); return qtrue; } /* ================= G_ScriptAction_PlayAnim syntax: playanim [looping ] [rate ] NOTE: all source animations must be at 20fps ================= */ qboolean G_ScriptAction_PlayAnim( gentity_t *ent, char *params ) { char *pString, *token, tokens[2][MAX_QPATH]; int i; // TTimo might be used uninitialized int endtime = 0; qboolean looping = qfalse, forever = qfalse; int startframe, endframe, idealframe; int rate = 20; if ( ( ent->scriptStatus.scriptFlags & SCFL_ANIMATING ) && ( ent->scriptStatus.scriptStackChangeTime == level.time ) ) { // this is a new call, so cancel the previous animation ent->scriptStatus.scriptFlags &= ~SCFL_ANIMATING; } pString = params; for ( i = 0; i < 2; i++ ) { token = COM_ParseExt( &pString, qfalse ); if ( !token || !token[0] ) { G_Printf( "G_Scripting: syntax error\n\nplayanim [LOOPING ]\n" ); return qtrue; } else { Q_strncpyz( tokens[i], token, sizeof( tokens[i] ) ); } } startframe = atoi( tokens[0] ); endframe = atoi( tokens[1] ); // check for optional parameters token = COM_ParseExt( &pString, qfalse ); if ( token[0] ) { if ( !Q_stricmp( token, "looping" ) ) { looping = qtrue; token = COM_ParseExt( &pString, qfalse ); if ( !token || !token[0] ) { G_Printf( "G_Scripting: syntax error\n\nplayanim [LOOPING ]\n" ); return qtrue; } if ( !Q_stricmp( token, "untilreachmarker" ) ) { if ( level.time < ent->s.pos.trTime + ent->s.pos.trDuration ) { endtime = level.time + 100; } else { endtime = 0; } } else if ( !Q_stricmp( token, "forever" ) ) { ent->scriptStatus.animatingParams = params; ent->scriptStatus.scriptFlags |= SCFL_ANIMATING; endtime = level.time + 100; // we don't care when it ends, since we are going forever! forever = qtrue; } else { endtime = ent->scriptStatus.scriptStackChangeTime + atoi( token ); } token = COM_ParseExt( &pString, qfalse ); } if ( token[0] && !Q_stricmp( token, "rate" ) ) { token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: playanim has RATE parameter without an actual rate specified" ); } rate = atoi( token ); } if ( !looping ) { endtime = ent->scriptStatus.scriptStackChangeTime + ( ( endframe - startframe ) * ( 1000 / 20 ) ); } } idealframe = startframe + (int)floor( (float)( level.time - ent->scriptStatus.scriptStackChangeTime ) / ( 1000.0 / (float)rate ) ); if ( looping ) { ent->s.frame = startframe + ( idealframe - startframe ) % ( endframe - startframe ); } else { if ( idealframe > endframe ) { ent->s.frame = endframe; } else { ent->s.frame = idealframe; } } if ( forever ) { return qtrue; // continue to the next command } return ( endtime <= level.time ); }; /* ================= G_ScriptAction_AlertEntity syntax: alertentity Arnout: modified to target multiple entities with the same targetname ================= */ qboolean G_ScriptAction_AlertEntity( gentity_t *ent, char *params ) { gentity_t *alertent = NULL; qboolean foundalertent = qfalse; int hash; if ( !params || !*params ) { G_Error( "G_Scripting: alertentity without targetname\n" ); } hash = BG_StringHashValue( params ); // find this targetname while ( 1 ) { alertent = G_FindByTargetnameFast( alertent, params, hash ); if ( !alertent ) { if ( !foundalertent ) { G_Error( "G_Scripting: alertentity cannot find targetname \"%s\"\n", params ); } else { break; } } foundalertent = qtrue; if ( alertent->client ) { // call this entity's AlertEntity function if ( !alertent->AIScript_AlertEntity ) { G_Error( "G_Scripting: alertentity \"%s\" (classname = %s) doesn't have an \"AIScript_AlertEntity\" function\n", params, alertent->classname ); } alertent->AIScript_AlertEntity( alertent ); } else { if ( !alertent->use ) { G_Error( "G_Scripting: alertentity \"%s\" (classname = %s) doesn't have a \"use\" function\n", params, alertent->classname ); } G_UseEntity( alertent, NULL, NULL ); } } return qtrue; } /* ================= G_ScriptAction_ToggleSpeaker syntax: togglespeaker ================= */ qboolean G_ScriptAction_ToggleSpeaker( gentity_t *ent, char *params ) { int i; long hash; gentity_t *tent; bg_speaker_t *speaker; if ( !params || !*params ) { G_Error( "G_Scripting: togglespeaker without targetname\n" ); } hash = BG_StringHashValue( params ); // find this targetname for ( i = 0; i < BG_NumScriptSpeakers(); i++ ) { speaker = BG_GetScriptSpeaker( i ); if ( hash != speaker->targetnamehash && Q_stricmp( params, speaker->targetname ) ) { continue; } tent = G_TempEntity( speaker->origin, EV_ALERT_SPEAKER ); tent->r.svFlags = SVF_BROADCAST; tent->s.otherEntityNum = i; tent->s.otherEntityNum2 = 0; } return qtrue; } /* ================= G_ScriptAction_DisableSpeaker syntax: disablespeaker ================= */ qboolean G_ScriptAction_DisableSpeaker( gentity_t *ent, char *params ) { int i; long hash; gentity_t *tent; bg_speaker_t *speaker; if ( !params || !*params ) { G_Error( "G_Scripting: disablespeaker without targetname\n" ); } hash = BG_StringHashValue( params ); // find this targetname for ( i = 0; i < BG_NumScriptSpeakers(); i++ ) { speaker = BG_GetScriptSpeaker( i ); if ( hash != speaker->targetnamehash && Q_stricmp( params, speaker->targetname ) ) { continue; } tent = G_TempEntity( speaker->origin, EV_ALERT_SPEAKER ); tent->r.svFlags = SVF_BROADCAST; tent->s.otherEntityNum = i; tent->s.otherEntityNum2 = 1; } return qtrue; } /* ================= G_ScriptAction_EnableSpeaker syntax: enablespeaker ================= */ qboolean G_ScriptAction_EnableSpeaker( gentity_t *ent, char *params ) { int i; long hash; gentity_t *tent; bg_speaker_t *speaker; if ( !params || !*params ) { G_Error( "G_Scripting: enablespeaker without targetname\n" ); } hash = BG_StringHashValue( params ); // find this targetname for ( i = 0; i < BG_NumScriptSpeakers(); i++ ) { speaker = BG_GetScriptSpeaker( i ); if ( hash != speaker->targetnamehash && Q_stricmp( params, speaker->targetname ) ) { continue; } tent = G_TempEntity( speaker->origin, EV_ALERT_SPEAKER ); tent->r.svFlags = SVF_BROADCAST; tent->s.otherEntityNum = i; tent->s.otherEntityNum2 = 2; } return qtrue; } /* ================= G_ScriptAction_Accum syntax: accum Commands: accum inc accum abort_if_less_than accum abort_if_greater_than accum abort_if_not_equal accum abort_if_equal accum set accum random accum bitset accum bitreset accum abort_if_bitset accum abort_if_not_bitset // Gordon: added (12/06/02) accum trigger_if_equal // Gordon: added (12/06/02) accum wait_while_equal ================= */ int BotGetTargetDynamite( int *list, int listSize, gentity_t* target ); qboolean G_ScriptAction_Accum( gentity_t *ent, char *params ) { char *pString, *token, lastToken[MAX_QPATH], name[MAX_QPATH]; int bufferIndex; qboolean terminate, found; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a buffer index\n" ); } bufferIndex = atoi( token ); if ( bufferIndex >= G_MAX_SCRIPT_ACCUM_BUFFERS ) { G_Error( "G_Scripting: accum buffer is outside range (0 - %i)\n", G_MAX_SCRIPT_ACCUM_BUFFERS ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a command\n" ); } Q_strncpyz( lastToken, token, sizeof( lastToken ) ); token = COM_ParseExt( &pString, qfalse ); if ( !Q_stricmp( lastToken, "inc" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] += atoi( token ); } else if ( !Q_stricmp( lastToken, "abort_if_less_than" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] < atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_greater_than" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] > atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_equal" ) || !Q_stricmp( lastToken, "abort_if_not_equals" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] != atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] == atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] |= ( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "bitreset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] &= ~( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "abort_if_bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] & ( 1 << atoi( token ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( !( ent->scriptAccumBuffer[bufferIndex] & ( 1 << atoi( token ) ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "set" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] = atoi( token ); } else if ( !Q_stricmp( lastToken, "random" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] = rand() % atoi( token ); } else if ( !Q_stricmp( lastToken, "trigger_if_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] == atoi( token ) ) { gentity_t* trent; int oldId; // qboolean loop = qfalse; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( lastToken, token, sizeof( lastToken ) ); if ( !*lastToken ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } // terminate = qfalse; found = qfalse; // for all entities/bots with this scriptName trent = NULL; while ( ( trent = G_Find( trent, FOFS( scriptName ), lastToken ) ) ) { found = qtrue; oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", name ); // if the script changed, return false so we don't muck with it's variables if ( ( trent == ent ) && ( oldId != trent->scriptStatus.scriptId ) ) { terminate = qtrue; } } // if ( terminate ) { return qfalse; } if ( found ) { return qtrue; } // // G_Error( "G_Scripting: trigger has unknown name: %s\n", name ); G_Printf( "G_Scripting: trigger has unknown name: %s\n", name ); return qtrue; } } else if ( !Q_stricmp( lastToken, "wait_while_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( ent->scriptAccumBuffer[bufferIndex] == atoi( token ) ) { return qfalse; } } else if ( !Q_stricmp( lastToken, "set_to_dynamitecount" ) ) { gentity_t* target; if ( !*token ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } target = G_FindByTargetname( NULL, token ); if ( !target ) { G_Error( "Scripting: accum %s could not find target\n", lastToken ); } ent->scriptAccumBuffer[bufferIndex] = BotGetTargetDynamite( NULL, 0, target ); } else { G_Error( "Scripting: accum %s: unknown command\n", params ); } return qtrue; } /* ================= G_ScriptAction_GlobalAccum syntax: globalAccum Commands: globalAccum inc globalAccum abort_if_less_than globalAccum abort_if_greater_than globalAccum abort_if_not_equal globalAccum abort_if_equal globalAccum set globalAccum random globalAccum bitset globalAccum bitreset globalAccum abort_if_bitset globalAccum abort_if_not_bitset // Gordon: added (12/06/02) globalAccum trigger_if_equal // Gordon: added (12/06/02) globalAccum wait_while_equal ================= */ qboolean G_ScriptAction_GlobalAccum( gentity_t *ent, char *params ) { char *pString, *token, lastToken[MAX_QPATH], name[MAX_QPATH]; int bufferIndex; qboolean terminate, found; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a buffer index\n" ); } bufferIndex = atoi( token ); if ( bufferIndex >= G_MAX_SCRIPT_ACCUM_BUFFERS ) { G_Error( "G_Scripting: accum buffer is outside range (0 - %i)\n", G_MAX_SCRIPT_ACCUM_BUFFERS ); } token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: accum without a command\n" ); } Q_strncpyz( lastToken, token, sizeof( lastToken ) ); token = COM_ParseExt( &pString, qfalse ); if ( !Q_stricmp( lastToken, "inc" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } level.globalAccumBuffer[bufferIndex] += atoi( token ); } else if ( !Q_stricmp( lastToken, "abort_if_less_than" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] < atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_greater_than" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] > atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_equal" ) || !Q_stricmp( lastToken, "abort_if_not_equals" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] != atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] == atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } level.globalAccumBuffer[bufferIndex] |= ( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "bitreset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } level.globalAccumBuffer[bufferIndex] &= ~( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "abort_if_bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] & ( 1 << atoi( token ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_bitset" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( !( level.globalAccumBuffer[bufferIndex] & ( 1 << atoi( token ) ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "set" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } level.globalAccumBuffer[bufferIndex] = atoi( token ); } else if ( !Q_stricmp( lastToken, "random" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } level.globalAccumBuffer[bufferIndex] = rand() % atoi( token ); } else if ( !Q_stricmp( lastToken, "trigger_if_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] == atoi( token ) ) { gentity_t* trent; int oldId; // qboolean loop = qfalse; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( lastToken, token, sizeof( lastToken ) ); if ( !*lastToken ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } terminate = qfalse; found = qfalse; // for all entities/bots with this scriptName trent = NULL; while ( ( trent = G_Find( trent, FOFS( scriptName ), lastToken ) ) ) { found = qtrue; oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", name ); // if the script changed, return false so we don't muck with it's variables if ( ( trent == ent ) && ( oldId != trent->scriptStatus.scriptId ) ) { terminate = qtrue; } } // if ( terminate ) { return qfalse; } if ( found ) { return qtrue; } // G_Error( "G_Scripting: trigger has unknown name: %s\n", name ); G_Printf( "G_Scripting: trigger has unknown name: %s\n", name ); return qtrue; } } else if ( !Q_stricmp( lastToken, "wait_while_equal" ) ) { if ( !token[0] ) { G_Error( "Scripting: accum %s requires a parameter\n", lastToken ); } if ( level.globalAccumBuffer[bufferIndex] == atoi( token ) ) { return qfalse; } } else { G_Error( "Scripting: accum %s: unknown command\n", params ); } return qtrue; } /* ================= G_ScriptAction_Print syntax: print Mostly for debugging purposes ================= */ qboolean G_ScriptAction_Print( gentity_t *ent, char *params ) { // Default to printing whole string char *printThis = params; char *pString, *token; int printLevel = 0; if ( !params || !params[0] ) { G_Error( "G_Scripting: print requires some text\n" ); } // Start parsing at the beginning of the string pString = params; // See if the first parameter is a /N, where N is a number if ( ( token = COM_ParseExt( &pString, qfalse ) ) && token[0] == '/' ) { // Get the integer version of the print debug level printLevel = atoi( &( token[1] ) ); // Just print what's left printThis = pString; } // Only print if our debug level is as high as the print level if ( g_scriptDebugLevel.integer >= printLevel ) { G_Printf( "(G_Script) %s-> %s\n", ent->scriptName, printThis ); } return qtrue; } /* ================= G_ScriptAction_FaceAngles syntax: faceangles [ACCEL/DECCEL] The entity will face the given angles, taking to get their. If the GOTOTIME is given instead of a timed duration, the duration calculated from the last gotomarker command will be used instead. ================= */ qboolean G_ScriptAction_FaceAngles( gentity_t *ent, char *params ) { char *pString, *token; int duration, i; vec3_t diff; vec3_t angles; int trType = TR_LINEAR_STOP; if ( !params || !params[0] ) { G_Error( "G_Scripting: syntax: faceangles \n" ); } if ( ent->scriptStatus.scriptStackChangeTime == level.time ) { pString = params; for ( i = 0; i < 3; i++ ) { token = COM_Parse( &pString ); if ( !token || !token[0] ) { G_Error( "G_Scripting: syntax: faceangles \n" ); } angles[i] = atoi( token ); } token = COM_Parse( &pString ); if ( !token || !token[0] ) { G_Error( "G_Scripting: faceangles requires a \n" ); } if ( !Q_stricmp( token, "gototime" ) ) { duration = ent->s.pos.trDuration; } else { duration = atoi( token ); } token = COM_Parse( &pString ); if ( token && token[0] ) { if ( !Q_stricmp( token, "accel" ) ) { trType = TR_ACCELERATE; } if ( !Q_stricmp( token, "deccel" ) ) { trType = TR_DECCELERATE; } } for ( i = 0; i < 3; i++ ) { diff[i] = AngleDifference( angles[i], ent->s.angles[i] ); while ( diff[i] > 180 ) diff[i] -= 360; while ( diff[i] < -180 ) diff[i] += 360; } VectorCopy( ent->s.angles, ent->s.apos.trBase ); if ( duration ) { VectorScale( diff, 1000.0 / (float)duration, ent->s.apos.trDelta ); } else { VectorClear( ent->s.apos.trDelta ); } ent->s.apos.trDuration = duration; ent->s.apos.trTime = level.time; ent->s.apos.trType = TR_LINEAR_STOP; if ( trType != TR_LINEAR_STOP ) { // accel / deccel logic // calc the speed from duration and start/end delta for ( i = 0; i < 3; i++ ) { ent->s.apos.trDelta[i] = 2.0 * 1000.0 * diff[i] / (float)duration; } ent->s.apos.trType = trType; } } else if ( ent->s.apos.trTime + ent->s.apos.trDuration <= level.time ) { // finished turning BG_EvaluateTrajectory( &ent->s.apos, ent->s.apos.trTime + ent->s.apos.trDuration, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); script_linkentity( ent ); return qtrue; } BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles, qtrue, ent->s.effect2Time ); script_linkentity( ent ); return qfalse; } /* =================== G_ScriptAction_ResetScript causes any currently running scripts to abort, in favour of the current script =================== */ qboolean G_ScriptAction_ResetScript( gentity_t *ent, char *params ) { if ( level.time == ent->scriptStatus.scriptStackChangeTime ) { return qfalse; } return qtrue; } /* =================== G_ScriptAction_TagConnect syntax: attachtotag connect this entity onto the tag of another entity =================== */ qboolean G_ScriptAction_TagConnect( gentity_t *ent, char *params ) { char *pString, *token; gentity_t *parent; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_TagConnect: syntax: attachtotag \n" ); } parent = G_FindByTargetname( NULL, token ); if ( !parent ) { parent = G_Find( NULL, FOFS( scriptName ), token ); if ( !parent ) { G_Error( "G_ScriptAction_TagConnect: unable to find entity with targetname \"%s\"", token ); } } token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_TagConnect: syntax: attachtotag \n" ); } ent->tagParent = parent; Q_strncpyz( ent->tagName, token, MAX_QPATH ); G_ProcessTagConnect( ent, qtrue ); // clear out the angles so it always starts out facing the tag direction VectorClear( ent->s.angles ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); return qtrue; } /* ==================== G_ScriptAction_Halt syntax: halt Stop moving. ==================== */ qboolean G_ScriptAction_Halt( gentity_t *ent, char *params ) { if ( level.time == ent->scriptStatus.scriptStackChangeTime ) { ent->scriptStatus.scriptFlags &= ~SCFL_GOING_TO_MARKER; // stop the angles BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->s.angles, qtrue, ent->s.effect2Time ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); VectorCopy( ent->s.angles, ent->r.currentAngles ); ent->s.apos.trTime = level.time; ent->s.apos.trDuration = 0; ent->s.apos.trType = TR_STATIONARY; VectorClear( ent->s.apos.trDelta ); // stop moving BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin, qfalse, ent->s.effect2Time ); VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); ent->s.pos.trTime = level.time; ent->s.pos.trDuration = 0; ent->s.pos.trType = TR_STATIONARY; VectorClear( ent->s.pos.trDelta ); script_linkentity( ent ); return qfalse; // kill any currently running script } else { return qtrue; } } /* =================== G_ScriptAction_StopSound syntax: stopsound Stops any looping sounds for this entity. =================== */ qboolean G_ScriptAction_StopSound( gentity_t *ent, char *params ) { ent->s.loopSound = 0; return qtrue; } /* ================= G_ScriptAction_EntityScriptName ================= */ qboolean G_ScriptAction_EntityScriptName( gentity_t *ent, char *params ) { trap_Cvar_Set( "g_scriptName", params ); return qtrue; } /* ================= G_ScriptAction_AIScriptName ================= */ qboolean G_ScriptAction_AIScriptName( gentity_t *ent, char *params ) { return qtrue; } // ----------------------------------------------------------------------- /* =================== G_ScriptAction_AxisRespawntime syntax: wm_axis_respawntime =================== */ qboolean G_ScriptAction_AxisRespawntime( gentity_t *ent, char *params ) { char *pString, *token; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_AxisRespawntime: time parameter required\n" ); } if ( g_userAxisRespawnTime.integer ) { trap_Cvar_Set( "g_redlimbotime", va( "%i", g_userAxisRespawnTime.integer * 1000 ) ); } else { trap_Cvar_Set( "g_redlimbotime", va( "%s000", token ) ); } return qtrue; } /* =================== G_ScriptAction_AlliedRespawntime syntax: wm_allied_respawntime =================== */ qboolean G_ScriptAction_AlliedRespawntime( gentity_t *ent, char *params ) { char *pString, *token; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_AlliedRespawntime: time parameter required\n" ); } if ( g_userAlliedRespawnTime.integer ) { trap_Cvar_Set( "g_bluelimbotime", va( "%i", g_userAlliedRespawnTime.integer * 1000 ) ); } else { trap_Cvar_Set( "g_bluelimbotime", va( "%s000", token ) ); } return qtrue; } /* =================== G_ScriptAction_NumberofObjectives syntax: wm_number_of_objectives =================== */ qboolean G_ScriptAction_NumberofObjectives( gentity_t *ent, char *params ) { char *pString, *token; char cs[MAX_STRING_CHARS]; int num; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_NumberofObjectives: number parameter required\n" ); } num = atoi( token ); if ( num < 1 || num > MAX_OBJECTIVES ) { G_Error( "G_ScriptAction_NumberofObjectives: Invalid number of objectives\n" ); } trap_GetConfigstring( CS_MULTI_INFO, cs, sizeof( cs ) ); Info_SetValueForKey( cs, "numobjectives", token ); trap_SetConfigstring( CS_MULTI_INFO, cs ); return qtrue; } /* =================== G_ScriptAction_SetMainObjective syntax: wm_set_main_objective =================== */ qboolean G_ScriptAction_SetMainObjective( gentity_t *ent, char *params ) { /* char *pString, *token; char cs[MAX_STRING_CHARS]; char* parm; int num, cs_obj; pString = params; token = COM_Parse(&pString); if (!token[0]) { G_Error( "G_ScriptAction_ObjectiveImage: number parameter required\n" ); } num = atoi( token ); if ( num < 1 || num > MAX_OBJECTIVES ) { G_Error( "G_ScriptAction_ObjectiveImage: Invalid objective number\n" ); } parm = va("%i", num); token = COM_Parse(&pString); if (!token[0]) { G_Error( "G_ScriptAction_ObjectiveImage: team parameter required\n" ); } cs_obj = !atoi(token) ? CS_MAIN_AXIS_OBJECTIVE : CS_MAIN_ALLIES_OBJECTIVE; trap_GetConfigstring( cs_obj, cs, sizeof(cs) ); if ( Q_stricmp( cs , parm ) ) { trap_SetConfigstring( cs_obj, parm ); }*/ return qtrue; } /* =================== G_ScriptAction_ObjectiveStatus syntax: wm_objective_status =================== */ qboolean G_ScriptAction_ObjectiveStatus( gentity_t *ent, char *params ) { char *pString, *token; char cs[MAX_STRING_CHARS]; char* parm; int num; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_ObjectiveImage: number parameter required\n" ); } num = atoi( token ); if ( num < 1 || num > MAX_OBJECTIVES ) { G_Error( "G_ScriptAction_ObjectiveImage: Invalid objective number\n" ); } token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_ObjectiveImage: team parameter required\n" ); } parm = atoi( token ) == 0 ? "x" : "a"; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_ObjectiveImage: status parameter required\n" ); } if ( atoi( token ) != 0 && atoi( token ) != 1 && atoi( token ) != 2 ) { G_Error( "G_ScriptAction_ObjectiveImage: status parameter must be 0 (default), 1 (complete) or 2 (failed)\n" ); } trap_GetConfigstring( CS_MULTI_OBJECTIVE, cs, sizeof( cs ) ); Info_SetValueForKey( cs, va( "%s%i", parm, num ), token ); trap_SetConfigstring( CS_MULTI_OBJECTIVE, cs ); return qtrue; } qboolean G_ScriptAction_SetDebugLevel( gentity_t *ent, char *params ) { char *pString, *token; int debugLevel = 0; if ( !params || !params[0] ) { G_Error( "G_ScriptAction_SetDebugLevel: requires integer level\n" ); } // Start parsing at the beginning of the string pString = params; // See if the first parameter is a /N, where N is a number if ( ( token = COM_ParseExt( &pString, qfalse ) ) && token[0] ) { // Get the integer version of the debug level debugLevel = atoi( token ); // Set the debug level trap_Cvar_Set( "g_scriptDebugLevel", va( "%i", debugLevel ) ); } return qtrue; } qboolean G_ScriptAction_VoiceAnnounce( gentity_t *ent, char *params ) { char *pString, *token; int num, sysmsg; if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_VoiceAnnounce: team parameter required\n" ); } num = atoi( token ); if ( num != 0 && num != 1 ) { G_Error( "G_ScriptAction_VoiceAnnounce: Invalid team number\n" ); } token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_VoiceAnnounce: system message parameter required\n" ); } sysmsg = G_GetSysMessageNumber( token ); if ( sysmsg == -1 ) { G_Error( "G_ScriptAction_VoiceAnnounce: invalid system message\n" ); } G_SendSystemMessage( sysmsg, !num ? TEAM_AXIS : TEAM_ALLIES ); return qtrue; } /* =================== G_ScriptAction_SetWinner syntax: wm_setwinner team: 0==AXIS, 1==ALLIED =================== */ qboolean G_ScriptAction_SetWinner( gentity_t *ent, char *params ) { char *pString, *token; char cs[MAX_STRING_CHARS]; int num; if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_SetWinner: number parameter required\n" ); } num = atoi( token ); if ( num < -1 || num > 1 ) { G_Error( "G_ScriptAction_SetWinner: Invalid team number\n" ); } if ( g_gametype.integer == GT_WOLF_LMS ) { num = -1; } trap_GetConfigstring( CS_MULTI_MAPWINNER, cs, sizeof( cs ) ); Info_SetValueForKey( cs, "winner", token ); trap_SetConfigstring( CS_MULTI_MAPWINNER, cs ); return qtrue; } /* =================== G_ScriptAction_SetDefendingTeam syntax: wm_set_objective_status status: 0==axis, 1==allies NERVE - SMF - sets defending team for stopwatch mode =================== */ qboolean G_ScriptAction_SetDefendingTeam( gentity_t *ent, char *params ) { char *pString, *token; char cs[MAX_STRING_CHARS]; int num; if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_SetDefendingTeam: number parameter required\n" ); } num = atoi( token ); if ( num < 0 || num > 1 ) { G_Error( "G_ScriptAction_SetDefendingTeam: Invalid team number\n" ); } trap_GetConfigstring( CS_MULTI_INFO, cs, sizeof( cs ) ); Info_SetValueForKey( cs, "defender", token ); trap_SetConfigstring( CS_MULTI_INFO, cs ); return qtrue; } /* =================== G_ScriptAction_AddTeamVoiceAnnounce syntax: wm_addteamvoiceannounce =================== */ qboolean G_ScriptAction_AddTeamVoiceAnnounce( gentity_t *ent, char *params ) { char *pString, *token; int team, i, index; if ( g_gamestate.integer != GS_PLAYING ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_AddTeamVoiceAnnounce: team parameter required\n" ); } if ( atoi( token ) ) { team = 1; } else { team = 0; } token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_AddTeamVoiceAnnounce: sound parameter required\n" ); } index = G_SoundIndex( token ); for ( i = 0; i < MAX_COMMANDER_TEAM_SOUNDS; i++ ) { if ( level.commanderSounds[team][i].index == index + 1 ) { return qtrue; // already exists } } for ( i = 0; i < MAX_COMMANDER_TEAM_SOUNDS; i++ ) { if ( !level.commanderSounds[team][i].index ) { level.commanderSounds[team][i].index = index + 1; break; } } return qtrue; } qboolean G_ScriptAction_RemoveTeamVoiceAnnounce( gentity_t *ent, char *params ) { char *pString, *token; int team; int index, i; pString = params; token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_RemoveTeamVoiceAnnounce: team parameter required\n" ); } if ( atoi( token ) ) { team = 1; } else { team = 0; } token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_RemoveTeamVoiceAnnounce: sound parameter required\n" ); } index = G_SoundIndex( token ); for ( i = 0; i < MAX_COMMANDER_TEAM_SOUNDS; i++ ) { if ( index + 1 == level.commanderSounds[team][i].index ) { level.commanderSounds[team][i].index = 0; } } return qtrue; } /* =================== G_ScriptAction_TeamVoiceAnnounce syntax: wm_teamvoiceannounce =================== */ qboolean G_ScriptAction_TeamVoiceAnnounce( gentity_t *ent, char *params ) { char *pString, *token; team_t team; gentity_t* tent; if ( g_gamestate.integer != GS_PLAYING ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_TeamVoiceAnnounce: team parameter required\n" ); } if ( atoi( token ) ) { team = TEAM_ALLIES; } else { team = TEAM_AXIS; } token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_TeamVoiceAnnounce: sound parameter required\n" ); } tent = G_TempEntity( vec3_origin, EV_GLOBAL_TEAM_SOUND ); tent->s.teamNum = team; tent->s.eventParm = G_SoundIndex( token ); tent->r.svFlags = SVF_BROADCAST; return qtrue; } /* =================== G_ScriptAction_Announce syntax: wm_announce_icon <"text to send to all clients"> =================== */ qboolean G_ScriptAction_Announce_Icon( gentity_t *ent, char *params ) { char *pString, *token; int iconnumber; if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_Announce_Icon: icon index parameter required\n" ); } iconnumber = atoi( token ); if ( iconnumber < 0 || iconnumber >= PM_NUM_TYPES ) { G_Error( "G_ScriptAction_Announce_Icon: icon index parameter out of range %i\n", iconnumber ); } token = COM_Parse( &pString ); if ( !*token ) { G_Error( "G_ScriptAction_Announce_Icon: statement parameter required\n" ); } trap_SendServerCommand( -1, va( "cpmi %i \"%s\"", iconnumber, token ) ); return qtrue; } /* =================== G_ScriptAction_Announce syntax: wm_announce <"text to send to all clients"> =================== */ qboolean G_ScriptAction_Announce( gentity_t *ent, char *params ) { char *pString, *token; if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_Announce: statement parameter required\n" ); } trap_SendServerCommand( -1, va( "cpm \"%s\"", token ) ); // trap_SendServerCommand( -1, va("cp \"%s\" 2", token )); return qtrue; } /* =================== G_ScriptAction_EndRound syntax: wm_endround <> =================== */ extern void LogExit( const char *string ); qboolean G_ScriptAction_EndRound( gentity_t *ent, char *params ) { if ( g_gamestate.integer == GS_INTERMISSION ) { return qtrue; } LogExit( "Wolf EndRound." ); return qtrue; } /* =================== G_ScriptAction_SetRoundTimelimit syntax: wm_set_round_timelimit =================== */ qboolean G_ScriptAction_SetRoundTimelimit( gentity_t *ent, char *params ) { char *pString, *token; float nextTimeLimit; pString = params; token = COM_Parse( &pString ); if ( !token[0] ) { G_Error( "G_ScriptAction_SetRoundTimelimit: number parameter required\n" ); } // NERVE - SMF nextTimeLimit = g_nextTimeLimit.value; if ( g_gametype.integer == GT_WOLF_STOPWATCH && nextTimeLimit ) { trap_Cvar_Set( "timelimit", va( "%f", nextTimeLimit ) ); } else if ( g_gametype.integer == GT_WOLF_LMS ) { if ( g_userTimeLimit.integer ) { int timelimit = g_userTimeLimit.integer < 3 ? 3 : g_userTimeLimit.integer; trap_Cvar_Set( "timelimit", va( "%i", timelimit ) ); } else { trap_Cvar_Set( "timelimit", token ); } } else { if ( g_userTimeLimit.integer ) { trap_Cvar_Set( "timelimit", va( "%i", g_userTimeLimit.integer ) ); } else { trap_Cvar_Set( "timelimit", token ); } } return qtrue; } /* =================== G_ScriptAction_RemoveEntity syntax: remove =================== */ qboolean G_ScriptAction_RemoveEntity( gentity_t *ent, char *params ) { ent->think = G_FreeEntity; ent->nextthink = level.time + FRAMETIME; return qtrue; } /* =================== G_ScriptAction_SetDamagable =================== */ qboolean G_ScriptAction_SetDamagable( gentity_t *ent, char *params ) { gentity_t *target; char *pString, name[MAX_QPATH], state[MAX_QPATH], *token; qboolean canDamage; pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !name[0] ) { G_Error( "G_Scripting: setdamagable must have a name and an state\n" ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( state, token, sizeof( state ) ); if ( !state[0] ) { G_Error( "G_Scripting: setdamagable must have a name and an state\n" ); } canDamage = atoi( state ) == 1 ? qtrue : qfalse; // look for entities target = &g_entities[MAX_CLIENTS - 1]; while ( ( target = G_FindByTargetname( target, name ) ) ) { target->takedamage = canDamage; } return qtrue; } /* =================== G_ScriptAction_SetState syntax: remove =================== */ qboolean G_ScriptAction_SetState( gentity_t *ent, char *params ) { gentity_t *target; char *pString, name[MAX_QPATH], state[MAX_QPATH], *token; entState_t entState = STATE_DEFAULT; int hash; qboolean found = qfalse; // get the cast name pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: setstate must have a name and an state\n" ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( state, token, sizeof( state ) ); if ( !state[0] ) { G_Error( "G_Scripting: setstate must have a name and an state\n" ); } if ( !Q_stricmp( state, "default" ) ) { entState = STATE_DEFAULT; } else if ( !Q_stricmp( state, "invisible" ) ) { entState = STATE_INVISIBLE; } else if ( !Q_stricmp( state, "underconstruction" ) ) { entState = STATE_UNDERCONSTRUCTION; } else { G_Error( "G_Scripting: setstate with invalid state '%s'\n", state ); } // look for an entities target = &g_entities[MAX_CLIENTS - 1]; hash = BG_StringHashValue( name ); while ( 1 ) { target = G_FindByTargetnameFast( target, name, hash ); if ( !target ) { if ( !found ) { G_Printf( "^1Warning: setstate called and no entities found\n" ); } break; } found = qtrue; G_SetEntState( target, entState ); } return qtrue; } extern void Cmd_StartCamera_f( gentity_t *ent ); extern void Cmd_StopCamera_f( gentity_t *ent ); /* =================== G_ScriptAction_StartCam syntax: startcam =================== */ qboolean G_ScriptAction_StartCam( gentity_t *ent, char *params ) { char *pString, *token; char camfile[256]; if ( !ent->client ) { return qfalse; } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_StartCam: filename parameter required\n" ); } Q_strncpyz( camfile, token, sizeof( camfile ) ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_StartCam: black parameter required\n" ); } Cmd_StartCamera_f( ent ); // issue a start camera command to the client trap_SendServerCommand( ent - g_entities, va( "startCam %s %d", camfile, (int)atoi( token ) ) ); return qtrue; } /* =================== G_ScriptAction_SetInitialCamera syntax: SetInitialCamera =================== */ qboolean G_ScriptAction_SetInitialCamera( gentity_t *ent, char *params ) { char *pString, *token; char camfile[256]; if ( !ent->client ) { return qfalse; } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_SetInitialCamera: filename parameter required\n" ); } Q_strncpyz( camfile, token, sizeof( camfile ) ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_SetInitialCamera: black parameter required\n" ); } // Cmd_StartCamera_f( ent ); // issue a start camera command to the client trap_SendServerCommand( ent - g_entities, va( "SetInitialCamera %s %d", camfile, (int)atoi( token ) ) ); return qtrue; } /* =================== G_ScriptAction_StopCam syntax: stopcam =================== */ qboolean G_ScriptAction_StopCam( gentity_t *ent, char *params ) { if ( !ent->client ) { return qfalse; } trap_SendServerCommand( ent - g_entities, "stopCam" ); return qtrue; } /* =================== G_ScriptAction_RepairMG42 syntax: repairmg42 =================== */ qboolean G_ScriptAction_RepairMG42( gentity_t *ent, char *params ) { gentity_t *target; char *pString, name[MAX_QPATH], *token; pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !name[0] ) { G_Error( "G_Scripting: repairmg42 must have a target\n" ); } // look for entities target = &g_entities[MAX_CLIENTS - 1]; while ( ( target = G_FindByTargetname( target, name ) ) ) { if ( target->takedamage ) { continue; } if ( target->s.eType != ET_MG42_BARREL ) { continue; } target->s.frame = 0; if ( target->mg42BaseEnt > 0 ) { g_entities[ target->mg42BaseEnt ].health = MG42_MULTIPLAYER_HEALTH; g_entities[ target->mg42BaseEnt ].takedamage = qtrue; target->health = 0; } else { target->health = MG42_MULTIPLAYER_HEALTH; } target->takedamage = qtrue; target->s.eFlags &= ~EF_SMOKING; } return qtrue; } /* =================== G_ScriptAction_SetHQStatus syntax: sethqstatus =================== */ qboolean G_ScriptAction_SetHQStatus( gentity_t *ent, char *params ) { char *pString, *token; team_t team; qboolean exists = qfalse; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: sethqstatus must have a team\n" ); } team = atoi( token ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: sethqstatus must have a status\n" ); } exists = atoi( token ); // just in case if ( !level.gameManager ) { return qtrue; } if ( team == 0 ) { level.gameManager->s.modelindex = exists; } else if ( team == 1 ) { level.gameManager->s.modelindex2 = exists; } else { G_Error( "G_Scripting: sethqstatus with bad team set" ); } return qtrue; } // Mad Doc - TDF /* =================== G_ScriptAction_PrintAccum syntax: printaccum prints out the value of accum 'accumNumber' =================== */ qboolean G_ScriptAction_PrintAccum( gentity_t *ent, char *params ) { char *token, *pString; int bufferIndex; if ( !params || !params[0] ) { G_Error( "G_ScriptAction_PrintAccum: syntax: PrintAccum \n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_PrintAccum: syntax: PrintAccum \n" ); } bufferIndex = atoi( token ); if ( ( bufferIndex < 0 ) || ( bufferIndex >= MAX_SCRIPT_ACCUM_BUFFERS ) ) { G_Error( "G_ScriptAction_PrintAccum: buffer is outside range (0 - %i)", MAX_SCRIPT_ACCUM_BUFFERS ); } G_Printf( "(G_Script) %s: Accum[%i] = %d\n", ent->scriptName, bufferIndex, ent->scriptAccumBuffer[bufferIndex] ); return qtrue; } // Mad Doc - TDF /* =================== G_ScriptAction_PrintGlobalAccum syntax: printGlobalAccum prints out the value of global accum 'globalaccumnumber' =================== */ qboolean G_ScriptAction_PrintGlobalAccum( gentity_t *ent, char *params ) { char *token, *pString; int bufferIndex; if ( !params || !params[0] ) { G_Error( "G_ScriptAction_PrintGlobalAccum: syntax: PrintGlobalAccum \n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_PrintGlobalAccum: syntax: PrintGlobalAccum \n" ); } bufferIndex = atoi( token ); if ( ( bufferIndex < 0 ) || ( bufferIndex >= MAX_SCRIPT_ACCUM_BUFFERS ) ) { G_Error( "PrintGlobalAccum: buffer is outside range (0 - %i)", MAX_SCRIPT_ACCUM_BUFFERS ); } G_Printf( "(G_Script) GlobalAccum[%i] = %d\n", bufferIndex, level.globalAccumBuffer[bufferIndex] ); return qtrue; } // Mad Doc - TDF /* =================== G_ScriptAction_RemoveBot syntax: RemoveBot removes the bot called 'botname' =================== */ qboolean G_ScriptAction_RemoveBot( gentity_t *ent, char *params ) { char *token, *pString; if ( !params || !params[0] ) { G_Error( "G_ScriptAction_RemoveBot: syntax: RemoveBot \n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_RemoveBot: syntax: RemoveBot \n" ); } G_RemoveNamedBot( token ); return qtrue; } // Mad Doc - TDF /* =================== G_ScriptAction_BotDebugging syntax: BotDebugging ON/OFF toggles bot debugging =================== */ qboolean G_ScriptAction_BotDebugging( gentity_t *ent, char *params ) { char *token, *pString; if ( !params || !params[0] ) { G_Error( "G_ScriptAction_BotDebugging: syntax: RemoveBot \n" ); } pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_ScriptAction_BotDebugging: syntax: RemoveBot \n" ); } if ( !Q_stricmp( token, "ON" ) ) { trap_Cvar_Set( "bot_debug", "1" ); } else if ( !Q_stricmp( token, "OFF" ) ) { trap_Cvar_Set( "bot_debug", "0" ); } else { G_Error( "G_ScriptAction_BotDebugging: syntax: RemoveBot \n" ); } return qtrue; } qboolean G_IsValidBotStateGoal( gentity_t* ent ) { switch ( ent->s.eType ) { case ET_MOVER: if ( !Q_stricmp( ent->classname, "func_static" ) ) { return qfalse; } return qtrue; case ET_TRIGGER_MULTIPLE: case ET_CONSTRUCTIBLE: case ET_OID_TRIGGER: case ET_ATTRACTOR_HINT: case ET_LANDMINE_HINT: case ET_SNIPER_HINT: case ET_LANDMINESPOT_HINT: case ET_EXPLOSIVE: return qtrue; case ET_MG42_BARREL: return qtrue; default: break; } return qfalse; } /* ================= G_ScriptAction_SetBotGoalState ================= */ qboolean G_ScriptAction_SetBotGoalState( gentity_t *ent, char *params ) { gentity_t *target; char *pString, name[MAX_QPATH], *token; qboolean entState = qtrue; qboolean teamFlags[2] = { qtrue, qtrue }; // default to both int hash; // get the cast name pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: setbotgoalstate must have a name and an state\n" ); } while ( ( token = COM_ParseExt( &pString, qfalse ) ) && token && token[0] ) { if ( !Q_stricmp( token, "axis" ) ) { teamFlags[0] = qtrue; teamFlags[1] = qfalse; } else if ( !Q_stricmp( token, "allies" ) ) { teamFlags[0] = qfalse; teamFlags[1] = qtrue; } else if ( !Q_stricmp( token, "both" ) ) { teamFlags[0] = qtrue; teamFlags[1] = qtrue; } else if ( !Q_stricmp( token, "inactive" ) ) { entState = qtrue; } else if ( !Q_stricmp( token, "active" ) ) { entState = qfalse; } else { G_Error( "G_Scripting: setbotgoalstate with invalid state '%s'\n", token ); } } // look for an entities target = &g_entities[MAX_CLIENTS - 1]; hash = BG_StringHashValue( name ); while ( ( target = G_FindByTargetnameFast( target, name, hash ) ) ) { if ( !G_IsValidBotStateGoal( target ) ) { continue; } if ( teamFlags[0] ) { if ( entState ) { target->aiInactive |= ( 1 << TEAM_AXIS ); } else { target->aiInactive &= ~( 1 << TEAM_AXIS ); } } if ( teamFlags[1] ) { if ( entState ) { target->aiInactive |= ( 1 << TEAM_ALLIES ); } else { target->aiInactive &= ~( 1 << TEAM_ALLIES ); } } } return qtrue; } /* ================= G_ScriptAction_SetAASState ================= */ qboolean G_ScriptAction_SetAASState( gentity_t *ent, char *params ) { gentity_t* target = NULL; char targetname[MAX_QPATH]; char *pString, *token; int flags, hash; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token || !*token ) { G_Error( "G_Scripting: setaasstate must have a name and a state [enabled|disabled|avoid]\n" ); } Q_strncpyz( targetname, token, sizeof( targetname ) ); token = COM_ParseExt( &pString, qfalse ); if ( !token || !*token ) { G_Error( "G_Scripting: setaasstate must have a name and a state [enabled|disabled|avoid]\n" ); } if ( !Q_stricmp( token, "enabled" ) ) { flags = AAS_AREA_ENABLED; } else if ( !Q_stricmp( token, "disabled" ) ) { flags = AAS_AREA_DISABLED; } else if ( !Q_stricmp( token, "avoid" ) ) { flags = AAS_AREA_AVOID; } else { G_Error( "G_Scripting: setaasstate: invalid state: %s\n", token ); return qtrue; } hash = BG_StringHashValue( targetname ); while ( ( target = G_FindByTargetnameFast( target, targetname, hash ) ) ) { if ( target->r.linked ) { G_SetAASBlockingEntity( target, flags ); } else { trap_LinkEntity( target ); G_SetAASBlockingEntity( target, flags ); trap_UnlinkEntity( target ); } } return qtrue; } /* ================= G_ScriptAction_SetBotGoalPriority ================= */ qboolean G_ScriptAction_SetBotGoalPriority( gentity_t *ent, char *params ) { gentity_t *target; char *pString, name[MAX_QPATH], *token; qboolean teamFlags[2] = { qtrue, qtrue }; // default to both int priority = 0; int hash; // get the cast name pString = params; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: setbotgoalpriority must have a name and a level\n" ); } while ( ( token = COM_ParseExt( &pString, qfalse ) ) && token && token[0] ) { if ( !Q_stricmp( token, "axis" ) ) { teamFlags[0] = qtrue; teamFlags[1] = qfalse; } else if ( !Q_stricmp( token, "allies" ) ) { teamFlags[0] = qfalse; teamFlags[1] = qtrue; } else if ( !Q_stricmp( token, "both" ) ) { teamFlags[0] = qtrue; teamFlags[1] = qtrue; } else if ( !Q_stricmp( token, "level" ) ) { token = COM_ParseExt( &pString, qfalse ); if ( !token || !*token ) { G_Error( "G_Scripting: setbotgoalpriority has 'level' with no value\n" ); } priority = atoi( token ); } else { G_Error( "G_Scripting: setbotgoalpriority with invalid token '%s'\n", token ); } } // look for an entities target = &g_entities[MAX_CLIENTS - 1]; hash = BG_StringHashValue( name ); while ( ( target = G_FindByTargetnameFast( target, name, hash ) ) ) { if ( teamFlags[0] ) { target->goalPriority[0] = priority; } if ( teamFlags[1] ) { target->goalPriority[1] = priority; } } return qtrue; } void AutoBuildConstruction( gentity_t* constructible ); qboolean G_ScriptAction_Construct( gentity_t *ent, char *params ) { char *pString, *token; gentity_t* constructible; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"construct\" must have a targetname\n" ); } constructible = G_FindByTargetname( NULL, token ); if ( !constructible || !constructible->inuse || constructible->s.eType != ET_CONSTRUCTIBLE ) { G_Error( "G_Scripting: \"construct\" could not find entity with targetname: %s\n", token ); } AutoBuildConstruction( constructible ); return qtrue; } /* =================== G_ScriptAction_ConstructibleClass syntax: constructible_class =================== */ qboolean G_ScriptAction_ConstructibleClass( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_class\" must have a class value\n" ); } value = atoi( token ); if ( value <= 0 || value > NUM_CONSTRUCTIBLE_CLASSES ) { G_Error( "G_Scripting: \"constructible_class\" has a bad value %i\n", value ); } value--; ent->constructibleStats = g_constructible_classes[value]; ent->constructibleStats.weaponclass--; ent->health = ent->constructibleStats.health; return qtrue; } /* =================== G_ScriptAction_ConstructibleChargeBarReq syntax: constructible_chargebarreq =================== */ qboolean G_ScriptAction_ConstructibleChargeBarReq( gentity_t *ent, char *params ) { char *pString, *token; float value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_chargebarreq\" must have a fraction value\n" ); } value = atof( token ); if ( value < 0 ) { G_Error( "G_Scripting: \"constructible_chargebarreq\" has a bad value %f\n", value ); } ent->constructibleStats.chargebarreq = value; return qtrue; } /* =================== G_ScriptAction_ConstructibleConstructXPBonus syntax: constructible_constructxpbonus =================== */ qboolean G_ScriptAction_ConstructibleConstructXPBonus( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_constructxpbonus\" must have a xppoints value\n" ); } value = atoi( token ); if ( value < 0 ) { G_Error( "G_Scripting: \"constructible_constructxpbonus\" has a bad value %i\n", value ); } ent->constructibleStats.constructxpbonus = value; return qtrue; } /* =================== G_ScriptAction_ConstructibleDestructXPBonus syntax: constructible_destructxpbonus =================== */ qboolean G_ScriptAction_ConstructibleDestructXPBonus( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_destructxpbonus\" must have a xppoints value\n" ); } value = atoi( token ); if ( value < 0 ) { G_Error( "G_Scripting: \"constructible_destructxpbonus\" has a bad value %i\n", value ); } ent->constructibleStats.destructxpbonus = value; return qtrue; } /* =================== G_ScriptAction_ConstructibleHealth syntax: constructible_health =================== */ qboolean G_ScriptAction_ConstructibleHealth( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_health\" must have a health value\n" ); } value = atoi( token ); if ( value <= 0 ) { G_Error( "G_Scripting: \"constructible_health\" has a bad value %i\n", value ); } ent->constructibleStats.health = value; ent->health = ent->constructibleStats.health; return qtrue; } /* =================== G_ScriptAction_ConstructibleWeaponclass syntax: constructible_weaponclass =================== */ qboolean G_ScriptAction_ConstructibleWeaponclass( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_weaponclass\" must have a weapon class value\n" ); } value = atoi( token ); if ( value < 1 || value > 3 ) { G_Error( "G_Scripting: \"constructible_weaponclass\" has a bad value %i\n", value ); } ent->constructibleStats.weaponclass = value; ent->constructibleStats.weaponclass--; return qtrue; } /* =================== G_ScriptAction_ConstructibleDuration syntax: constructible_duration =================== */ qboolean G_ScriptAction_ConstructibleDuration( gentity_t *ent, char *params ) { char *pString, *token; int value; pString = params; if ( !( token = COM_ParseExt( &pString, qfalse ) ) ) { G_Error( "G_Scripting: \"constructible_duration\" must have a duration value\n" ); } value = atoi( token ); if ( value < 0 ) { G_Error( "G_Scripting: \"constructible_duration\" has a bad value %i\n", value ); } ent->constructibleStats.duration = value; return qtrue; } /* =================== G_ScriptAction_SpawnBot =================== */ qboolean G_ScriptAction_SpawnBot( gentity_t *ent, char *params ) { //trap_SendConsoleCommand( EXEC_APPEND, va("spawnbot %s\n", params) ); G_SpawnBot( params ); return qtrue; } /* =================== G_ScriptAction_Cvar syntax: cvar =================== */ qboolean G_ScriptAction_Cvar( gentity_t *ent, char *params ) { char *pString, *token, lastToken[MAX_QPATH], name[MAX_QPATH], cvarName[MAX_QPATH]; int cvarValue; qboolean terminate, found; pString = params; token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: cvar without a cvar name\n" ); } Q_strncpyz( cvarName, token, sizeof( cvarName ) ); cvarValue = trap_Cvar_VariableIntegerValue( cvarName ); token = COM_ParseExt( &pString, qfalse ); if ( !token[0] ) { G_Error( "G_Scripting: cvar without a command\n" ); } Q_strncpyz( lastToken, token, sizeof( lastToken ) ); token = COM_ParseExt( &pString, qfalse ); if ( !Q_stricmp( lastToken, "inc" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } trap_Cvar_Set( cvarName, va( "%i", cvarValue + 1 ) ); } else if ( !Q_stricmp( lastToken, "abort_if_less_than" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue < atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_greater_than" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue > atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_equal" ) || !Q_stricmp( lastToken, "abort_if_not_equals" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue != atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_equal" ) || !Q_stricmp( lastToken, "abort_if_equals" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue == atoi( token ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "bitset" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } cvarValue |= ( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "bitreset" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } cvarValue &= ~( 1 << atoi( token ) ); } else if ( !Q_stricmp( lastToken, "abort_if_bitset" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue & ( 1 << atoi( token ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "abort_if_not_bitset" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( !( cvarValue & ( 1 << atoi( token ) ) ) ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } } else if ( !Q_stricmp( lastToken, "set" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } cvarValue = atoi( token ); } else if ( !Q_stricmp( lastToken, "random" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } cvarValue = rand() % atoi( token ); } else if ( !Q_stricmp( lastToken, "trigger_if_equal" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue == atoi( token ) ) { gentity_t* trent; int oldId; // qboolean loop = qfalse; token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( lastToken, token, sizeof( lastToken ) ); if ( !*lastToken ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } token = COM_ParseExt( &pString, qfalse ); Q_strncpyz( name, token, sizeof( name ) ); if ( !*name ) { G_Error( "G_Scripting: trigger must have a name and an identifier: %s\n", params ); } terminate = qfalse; found = qfalse; // for all entities/bots with this scriptName trent = NULL; while ( ( trent = G_Find( trent, FOFS( scriptName ), lastToken ) ) ) { found = qtrue; oldId = trent->scriptStatus.scriptId; G_Script_ScriptEvent( trent, "trigger", name ); // if the script changed, return false so we don't muck with it's variables if ( ( trent == ent ) && ( oldId != trent->scriptStatus.scriptId ) ) { terminate = qtrue; } } // if ( terminate ) { return qfalse; } if ( found ) { return qtrue; } // // G_Error( "G_Scripting: trigger has unknown name: %s\n", name ); G_Printf( "G_Scripting: trigger has unknown name: %s\n", name ); return qtrue; } } else if ( !Q_stricmp( lastToken, "wait_while_equal" ) ) { if ( !token[0] ) { G_Error( "G_Scripting: cvar %s requires a parameter\n", lastToken ); } if ( cvarValue == atoi( token ) ) { return qfalse; } } else { G_Error( "G_Scripting: cvar %s: unknown command\n", params ); } return qtrue; } /* ===================== G_ScriptAction_AbortIfWarmup ===================== */ qboolean G_ScriptAction_AbortIfWarmup( gentity_t *ent, char *params ) { if ( level.warmupTime ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } // return qtrue; } /* ==================== G_ScriptAction_AbortIfNotSinglePlayer ==================== */ qboolean G_ScriptAction_AbortIfNotSinglePlayer( gentity_t *ent, char *params ) { if ( !G_IsSinglePlayerGame() ) { // abort the current script ent->scriptStatus.scriptStackHead = ent->scriptEvents[ent->scriptStatus.scriptEventIndex].stack.numItems; } // return qtrue; } /* =================== etpro_ScriptAction_SetValues Ikkyo - change key/value pairs of any entity syntax (example): set { origin "3510 -960 1280" classname "ookblat" etc etc } available fields can be found in field_t of g_spawn.c, it is quite simple to add new ones =================== */ qboolean etpro_ScriptAction_SetValues( gentity_t *ent, char *params ) { char *token; char *p; char key[MAX_TOKEN_CHARS], value[MAX_TOKEN_CHARS]; int classchanged = 0; // rain - reset and fill in the spawnVars info so that spawn // functions can use them level.numSpawnVars = 0; level.numSpawnVarChars = 0; p = params; // Get each key/value pair while ( 1 ) { token = COM_ParseExt( &p, qfalse ); if ( !token[0] ) { break; } strcpy( key, token ); token = COM_ParseExt( &p, qfalse ); if ( !token[0] ) { G_Error( "key \"%s\" has no value", key ); break; } strcpy( value, token ); if ( g_scriptDebug.integer ) { G_Printf( "%d : (%s) %s: set [%s] [%s] [%s]\n", level.time, ent->scriptName, GAMEVERSION, ent->scriptName, key, value ); } if ( !Q_stricmp( key, "classname" ) ) { if ( Q_stricmp( value, ent->classname ) ) { classchanged = 1; } } // rain - add spawn var so that spawn functions can use them if ( level.numSpawnVars == MAX_SPAWN_VARS ) { G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" ); } level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( key ); level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( value ); level.numSpawnVars++; G_ParseField( key, value, ent ); if ( !Q_stricmp( key, "targetname" ) ) { //need to hash this ent targetname for setstate script targets... ent->targetnamehash = BG_StringHashValue( ent->targetname ); } } // move editor origin to pos VectorCopy( ent->s.origin, ent->s.pos.trBase ); VectorCopy( ent->s.origin, ent->r.currentOrigin ); // rain - if the classname was changed, call the spawn func again if ( classchanged ) { G_CallSpawn( ent ); trap_LinkEntity( ent ); } // relink if once linked if ( ent->r.linked ) { trap_LinkEntity( ent ); } return qtrue; }