/* ============== G_Script_ScriptParse Parses the script for the given entity ============== */ void G_Script_ScriptParse(gentity_t *ent) { char *pScript; qboolean wantName; qboolean inScript; int eventNum; g_script_event_t events[G_MAX_SCRIPT_STACK_ITEMS]; int numEventItems; g_script_event_t *curEvent; char params[MAX_INFO_STRING]; g_script_stack_action_t *action; int i; int bracketLevel; qboolean buildScript; if (!ent->scriptName) { return; } if (!level.scriptEntity) { return; } buildScript = trap_Cvar_VariableIntegerValue("com_buildScript"); pScript = level.scriptEntity; wantName = qtrue; inScript = qfalse; COM_BeginParseSession("G_Script_ScriptParse"); bracketLevel = 0; numEventItems = 0; memset(events, 0, sizeof (events)); for (;;) { char *token; token = COM_Parse(&pScript); if (!token[0]) { if (!wantName) { G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine()); } break; } // end of script if (token[0] == '}') { if (inScript) { break; } if (wantName) { G_Error("G_Script_ScriptParse(), Error (line %d): '}' found, but not expected.\n", COM_GetCurrentParseLine()); } wantName = qtrue; } else if (token[0] == '{') { if (wantName) { G_Error("G_Script_ScriptParse(), Error (line %d): '{' found, NAME expected.\n", COM_GetCurrentParseLine()); } } else if (wantName) { if (!Q_stricmp(token, "bot")) { // a bot, skip this whole entry SkipRestOfLine(&pScript); // skip this section SkipBracedSection(&pScript); // continue; } if (!Q_stricmp(token, "entity")) { // this is an entity, so go back to look for a name continue; } if (!Q_stricmp(ent->scriptName, token)) { inScript = qtrue; numEventItems = 0; } wantName = qfalse; } else if (inScript) { Q_strlwr(token); eventNum = G_Script_EventForString(token); if (eventNum < 0) { G_Error("G_Script_ScriptParse(), Error (line %d): unknown event: %s.\n", COM_GetCurrentParseLine(), token); } if (numEventItems >= G_MAX_SCRIPT_STACK_ITEMS) { G_Error("G_Script_ScriptParse(), Error (line %d): G_MAX_SCRIPT_STACK_ITEMS reached (%d)\n", COM_GetCurrentParseLine(), G_MAX_SCRIPT_STACK_ITEMS); } curEvent = &events[numEventItems]; curEvent->eventNum = eventNum; memset(params, 0, sizeof (params)); // parse any event params before the start of this event's actions while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '{')) { if (!token[0]) { G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine()); } if (strlen(params)) { // add a space between each param Q_strcat(params, sizeof (params), " "); } Q_strcat(params, sizeof (params), token); } if (strlen(params)) { // copy the params into the event curEvent->params = G_Alloc(strlen(params) + 1); Q_strncpyz(curEvent->params, params, strlen(params) + 1); } // parse the actions for this event while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) { if (!token[0]) { G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine()); } action = G_Script_ActionForString(token); if (!action) { G_Error("G_Script_ScriptParse(), Error (line %d): unknown action: %s.\n", COM_GetCurrentParseLine(), token); } curEvent->stack.items[curEvent->stack.numItems].action = action; memset(params, 0, sizeof (params)); // Ikkyo - Parse for {}'s if this is a set command // Nico, added "create" & "delete" condition if (!Q_stricmp(action->actionString, "set") || !Q_stricmp(action->actionString, "create") || !Q_stricmp(action->actionString, "delete")) { token = COM_Parse(&pScript); if (token[0] != '{') { COM_ParseError("'{' expected, found: %s.\n", token); } while ((token = COM_Parse(&pScript)) != NULL && (token[0] != '}')) { if (strlen(params)) { // add a space between each param Q_strcat(params, sizeof (params), " "); } if (strrchr(token, ' ')) { // need to wrap this param in quotes since it has more than one word Q_strcat(params, sizeof (params), "\""); } Q_strcat(params, sizeof (params), token); if (strrchr(token, ' ')) { // need to wrap this param in quotes since it has mor Q_strcat(params, sizeof (params), "\""); } } } else // hackly precaching of custom characters if (!Q_stricmp(token, "spawnbot")) { // this is fairly indepth, so I'll move it to a separate function for readability G_Script_ParseSpawnbot(&pScript, params, MAX_INFO_STRING); } else { token = COM_ParseExt(&pScript, qfalse); for (i = 0; token[0]; ++i) { if (strlen(params)) { // add a space between each param Q_strcat(params, sizeof (params), " "); } if (i == 0) { // Special case: playsound's need to be cached on startup to prevent in-game pauses if (!Q_stricmp(action->actionString, "playsound")) { G_SoundIndex(token); } else if (!Q_stricmp(action->actionString, "changemodel")) { G_ModelIndex(token); } else if (buildScript && (!Q_stricmp(action->actionString, "mu_start") || !Q_stricmp(action->actionString, "mu_play") || !Q_stricmp(action->actionString, "mu_queue") || !Q_stricmp(action->actionString, "startcam")) && strlen(token)) { trap_SendServerCommand(-1, va("addToBuild %s\n", token)); } } if ((i == 0 || i == 1) && !Q_stricmp(action->actionString, "remapshader")) { G_ShaderIndex(token); } if (strrchr(token, ' ')) { // need to wrap this param in quotes since it has more than one word Q_strcat(params, sizeof (params), "\""); } Q_strcat(params, sizeof (params), token); if (strrchr(token, ' ')) { // need to wrap this param in quotes since it has more than one word Q_strcat(params, sizeof (params), "\""); } token = COM_ParseExt(&pScript, qfalse); } } if (strlen(params)) { // copy the params into the event curEvent->stack.items[curEvent->stack.numItems].params = G_Alloc(strlen(params) + 1); Q_strncpyz(curEvent->stack.items[curEvent->stack.numItems].params, params, strlen(params) + 1); } curEvent->stack.numItems++; if (curEvent->stack.numItems >= G_MAX_SCRIPT_STACK_ITEMS) { G_Error("G_Script_ScriptParse(): script exceeded G_MAX_SCRIPT_STACK_ITEMS (%d), line %d\n", G_MAX_SCRIPT_STACK_ITEMS, COM_GetCurrentParseLine()); } } numEventItems++; } else { // skip this character completely // TTimo gcc: suggest parentheses around assignment used as truth value while ((token = COM_Parse(&pScript)) != NULL) { if (!token[0]) { G_Error("G_Script_ScriptParse(), Error (line %d): '}' expected, end of script found.\n", COM_GetCurrentParseLine()); } else if (token[0] == '{') { bracketLevel++; } else if (token[0] == '}' && !--bracketLevel) { break; } } } } // alloc and copy the events into the gentity_t for this cast if (numEventItems > 0) { ent->scriptEvents = G_Alloc(sizeof (g_script_event_t) * numEventItems); memcpy(ent->scriptEvents, events, sizeof (g_script_event_t) * numEventItems); ent->numScriptEvents = numEventItems; } }
/* =============== G_ParseDmgScript =============== */ static int G_ParseDmgScript( damageRegion_t *regions, char *buf ) { char *token; float angleSpan, heightSpan; int count; for ( count = 0;; count++ ) { token = COM_Parse( &buf ); if ( !token[ 0 ] ) { break; } if ( strcmp( token, "{" ) ) { COM_ParseError( "Missing {" ); break; } if ( count >= MAX_DAMAGE_REGIONS ) { COM_ParseError( "Max damage regions exceeded" ); break; } // defaults regions[ count ].name[ 0 ] = '\0'; regions[ count ].minHeight = 0.0f; regions[ count ].maxHeight = 1.0f; regions[ count ].minAngle = 0.0f; regions[ count ].maxAngle = 360.0f; regions[ count ].modifier = 1.0f; regions[ count ].crouch = qfalse; while ( 1 ) { token = COM_ParseExt( &buf, qtrue ); if ( !token[ 0 ] ) { COM_ParseError( "Unexpected end of file" ); break; } if ( !Q_stricmp( token, "}" ) ) { break; } else if ( !strcmp( token, "name" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( token[ 0 ] ) { Q_strncpyz( regions[ count ].name, token, sizeof( regions[ count ].name ) ); } } else if ( !strcmp( token, "minHeight" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( !token[ 0 ] ) { strcpy( token, "0" ); } regions[ count ].minHeight = atof( token ); } else if ( !strcmp( token, "maxHeight" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( !token[ 0 ] ) { strcpy( token, "100" ); } regions[ count ].maxHeight = atof( token ); } else if ( !strcmp( token, "minAngle" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( !token[ 0 ] ) { strcpy( token, "0" ); } regions[ count ].minAngle = atoi( token ); } else if ( !strcmp( token, "maxAngle" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( !token[ 0 ] ) { strcpy( token, "360" ); } regions[ count ].maxAngle = atoi( token ); } else if ( !strcmp( token, "modifier" ) ) { token = COM_ParseExt( &buf, qfalse ); if ( !token[ 0 ] ) { strcpy( token, "1.0" ); } regions[ count ].modifier = atof( token ); } else if ( !strcmp( token, "crouch" ) ) { regions[ count ].crouch = qtrue; } else { COM_ParseWarning( "Unknown token \"%s\"", token ); } } // Angle portion covered angleSpan = regions[ count ].maxAngle - regions[ count ].minAngle; if ( angleSpan < 0.0f ) { angleSpan += 360.0f; } angleSpan /= 360.0f; // Height portion covered heightSpan = regions[ count ].maxHeight - regions[ count ].minHeight; if ( heightSpan < 0.0f ) { heightSpan = -heightSpan; } if ( heightSpan > 1.0f ) { heightSpan = 1.0f; } regions[ count ].area = angleSpan * heightSpan; if ( !regions[ count ].area ) { regions[ count ].area = 0.00001f; } } return count; }