/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2007 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Warzone 2100 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 Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ %{ /* * ScriptVals.y * * yacc grammar for loading script variable values * */ #include #include "lib/framework/frame.h" #include "lib/script/script.h" #include "scripttabs.h" #include "scriptvals.h" #include "objects.h" #include "lib/gamelib/gtime.h" #include "droid.h" #include "structure.h" #include "message.h" #include "lib/sound/audio.h" #include "levels.h" #include "research.h" extern int scrv_lex(void); // The current script code static SCRIPT_CODE *psCurrScript; // The current script context static SCRIPT_CONTEXT *psCurrContext; // the current array indexes static ARRAY_INDEXES sCurrArrayIndexes; // check that an array index is valid BOOL scrvCheckArrayIndex(SDWORD base, ARRAY_INDEXES *psIndexes, UDWORD *pIndex) { SDWORD i, size; if (!psCurrScript || psCurrScript->psDebug == NULL) { return FALSE; } if (base < 0 || base >= psCurrScript->numArrays) { scrv_error("Array index out of range"); return FALSE; } if (psIndexes->dimensions != psCurrScript->psArrayInfo[base].dimensions) { scrv_error("Invalid number of dimensions for array initialiser"); return FALSE; } for(i=0; ipsArrayInfo[base].dimensions; i++) { if ((psIndexes->elements[i] < 0) || (psIndexes->elements[i] >= psCurrScript->psArrayInfo[base].elements[i])) { scrv_error("Invalid index for dimension %d", i); return FALSE; } } *pIndex = 0; size = 1; for(i = psCurrScript->psArrayInfo[base].dimensions-1; i >= 0; i--) { *pIndex += psIndexes->elements[i] * size; size *= psCurrScript->psArrayInfo[base].elements[i]; } *pIndex += psCurrScript->psArrayInfo[base].base; return TRUE; } %} %name-prefix="scrv_" %union { BOOL bval; INTERP_TYPE tval; STRING *sval; UDWORD vindex; SDWORD ival; VAR_INIT sInit; ARRAY_INDEXES *arrayIndex; } /* value tokens */ %token BOOLEAN_T %token INTEGER %token IDENT %token QTEXT /* Text with double quotes surrounding it */ %token TYPE %token VAR %token ARRAY /* keywords */ %token SCRIPT %token STORE %token RUN /* rule types */ %type script_name %type var_value %type var_entry %type array_index %type array_index_list %% val_file: script_entry | val_file script_entry ; script_entry: script_name RUN { if (!eventNewContext(psCurrScript, CR_RELEASE, &psCurrContext)) { scrv_error("Couldn't create context"); YYABORT; } if (!scrvAddContext($1, psCurrContext, SCRV_EXEC)) { scrv_error("Couldn't store context"); YYABORT; } } '{' var_init_list '}' { if (!eventRunContext(psCurrContext, gameTime/SCR_TICKRATE)) { YYABORT; } } | script_name STORE QTEXT { if (!eventNewContext(psCurrScript, CR_NORELEASE, &psCurrContext)) { scrv_error("Couldn't create context"); YYABORT; } if (!scrvAddContext($3, psCurrContext, SCRV_NOEXEC)) { scrv_error("Couldn't store context"); YYABORT; } } '{' var_init_list '}' ; script_name: SCRIPT QTEXT { int namelen,extpos; char *stringname; stringname=$2; namelen=strlen( stringname); extpos=namelen-3; if (strncmp(&stringname[extpos],"blo",3)==0) { if (resPresent("BLO",stringname)==TRUE) { psCurrScript=resGetData("BLO",stringname); } else { // change extension to "slo" stringname[extpos]='s'; psCurrScript=resGetData("SCRIPT",stringname); } } else if (strncmp(&stringname[extpos],"slo",3)==0) { if (resPresent("SCRIPT",stringname)==TRUE) { psCurrScript=resGetData("SCRIPT",stringname); } } if (!psCurrScript) { scrv_error("Script file %s not found", stringname); YYABORT; } $$ = $2; } ; var_init_list: /* NULL token */ | var_init | var_init_list var_init ; var_init: var_entry TYPE var_value { BASE_OBJECT *psObj; SDWORD compIndex; DROID_TEMPLATE *psTemplate; VIEWDATA *psViewData; STRING *pString; RESEARCH *psResearch; switch ($2) { case VAL_INT: if ($3.type != IT_INDEX || !eventSetContextVar(psCurrContext, $1, $2, (UDWORD)$3.index)) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } break; case ST_DROID: if ($3.type != IT_INDEX) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetBaseObj((UDWORD)$3.index, &psObj)) { scrv_error("Droid id %d not found", (UDWORD)$3.index); YYABORT; } if (psObj->type != OBJ_DROID) { scrv_error("Object id %d is not a droid", (UDWORD)$3.index); YYABORT; } else { if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psObj)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_STRUCTURE: if ($3.type != IT_INDEX) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetBaseObj((UDWORD)$3.index, &psObj)) { scrv_error("Structure id %d not found", (UDWORD)$3.index); YYABORT; } if (psObj->type != OBJ_STRUCTURE) { scrv_error("Object id %d is not a structure", (UDWORD)$3.index); YYABORT; } else { if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psObj)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_FEATURE: if ($3.type != IT_INDEX) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetBaseObj((UDWORD)$3.index, &psObj)) { scrv_error("Feature id %d not found", (UDWORD)$3.index); YYABORT; } if (psObj->type != OBJ_FEATURE) { scrv_error("Object id %d is not a feature", (UDWORD)$3.index); YYABORT; } else { if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psObj)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_FEATURESTAT: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getFeatureStatFromName($3.pString); if (compIndex == -1) { scrv_error("Feature Stat %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case VAL_BOOL: if ($3.type != IT_BOOL || !eventSetContextVar(psCurrContext, $1, $2, (UDWORD)$3.index)) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } break; case ST_BODY: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_BODY, $3.pString); if (compIndex == -1) { scrv_error("body component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_PROPULSION: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_PROPULSION, $3.pString); if (compIndex == -1) { scrv_error("Propulsion component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_ECM: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_ECM, $3.pString); if (compIndex == -1) { scrv_error("ECM component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_SENSOR: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_SENSOR, $3.pString); if (compIndex == -1) { scrv_error("Sensor component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_CONSTRUCT: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_CONSTRUCT, $3.pString); if (compIndex == -1) { scrv_error("Construct component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_REPAIR: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_REPAIRUNIT, $3.pString); if (compIndex == -1) { scrv_error("Repair component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_BRAIN: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_BRAIN, $3.pString); if (compIndex == -1) { scrv_error("Brain component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_WEAPON: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getCompFromResName(COMP_WEAPON, $3.pString); if (compIndex == -1) { scrv_error("Weapon component %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_TEMPLATE: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } psTemplate = getTemplateFromName($3.pString); if (psTemplate == NULL) { scrv_error("Template %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psTemplate)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_STRUCTURESTAT: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } compIndex = getStructStatFromName($3.pString); if (compIndex == -1) { scrv_error("Structure Stat %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_STRUCTUREID: if ($3.type != IT_INDEX) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetBaseObj((UDWORD)$3.index, &psObj)) { scrv_error("Structure id %d not found", (UDWORD)$3.index); YYABORT; } if (psObj->type != OBJ_STRUCTURE) { scrv_error("Object id %d is not a structure", (UDWORD)$3.index); YYABORT; } else { if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)$3.index)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_DROIDID: if ($3.type != IT_INDEX) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetBaseObj((UDWORD)$3.index, &psObj)) { scrv_error("Droid id %d not found", (UDWORD)$3.index); YYABORT; } if (psObj->type != OBJ_DROID) { scrv_error("Object id %d is not a droid", (UDWORD)$3.index); YYABORT; } else { if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)$3.index)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_INTMESSAGE: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } psViewData = getViewData($3.pString); if (psViewData == NULL) { scrv_error("Message %s not found", $3.pString); YYABORT; } if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psViewData)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_TEXTSTRING: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } if (!scrvGetString($3.pString, &pString)) { scrv_error("String %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)pString)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_LEVEL: { LEVEL_DATASET *psLevel; if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } // just check the level exists if (!levFindDataSet($3.pString, &psLevel)) { scrv_error("Level %s not found", $3.pString); YYABORT; } if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psLevel->pName)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } } break; case ST_SOUND: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } /* find audio id */ compIndex = audio_GetTrackID( $3.pString ); if (compIndex == SAMPLE_NOT_FOUND) { /* set track vals */ audio_SetTrackVals( $3.pString, FALSE, &compIndex, 100, 1, 1800, 0 ); } /* save track ID */ if (!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)compIndex)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; case ST_RESEARCH: if ($3.type != IT_STRING) { scrv_error("Typemismatch for variable %d", $1); YYABORT; } psResearch = getResearch($3.pString, TRUE); if (psResearch == NULL) { scrv_error("Research %s not found", $3.pString); YYABORT; } if(!eventSetContextVar(psCurrContext, $1, $2, (UDWORD)psResearch)) { scrv_error("Set Value Failed for %s", $1); YYABORT; } break; default: scrv_error("Unknown type: %s", asTypeTable[$2].pIdent); YYABORT; break; } } ; array_index: '[' INTEGER ']' { sCurrArrayIndexes.dimensions = 1; sCurrArrayIndexes.elements[0] = $2; $$ = &sCurrArrayIndexes; } ; array_index_list: array_index { $$ = $1; } | array_index_list '[' INTEGER ']' { if ($1->dimensions >= VAR_MAX_DIMENSIONS) { scrv_error("Too many dimensions for array"); YYABORT; } $1->elements[$1->dimensions] = $3; $1->dimensions += 1; } ; var_entry: VAR { $$ = $1; } | ARRAY array_index_list { UDWORD index; if (!scrvCheckArrayIndex($1, $2, &index)) { YYABORT; } $$ = index; } ; var_value: BOOLEAN_T { $$.type = IT_BOOL; $$.index = $1; } | INTEGER { $$.type = IT_INDEX; $$.index = $1; } | QTEXT { $$.type = IT_STRING; $$.pString = $1; } ; %% // Lookup a type BOOL scrvLookUpType(STRING *pIdent, INTERP_TYPE *pType) { TYPE_SYMBOL *psCurr; for(psCurr = asTypeTable; psCurr->typeID != 0; psCurr++) { if (strcmp(psCurr->pIdent, pIdent) == 0) { *pType = psCurr->typeID; return TRUE; } } return FALSE; } // Lookup a variable identifier BOOL scrvLookUpVar(STRING *pIdent, UDWORD *pIndex) { UDWORD i; if (!psCurrScript || psCurrScript->psDebug == NULL) { return FALSE; } for(i=0; inumGlobals; i++) { if (psCurrScript->psVarDebug[i].pIdent != NULL && strcmp(psCurrScript->psVarDebug[i].pIdent, pIdent) == 0) { *pIndex = i; return TRUE; } } return FALSE; } // Lookup an array identifier BOOL scrvLookUpArray(STRING *pIdent, UDWORD *pIndex) { UDWORD i; if (!psCurrScript || psCurrScript->psDebug == NULL) { return FALSE; } for(i=0; inumArrays; i++) { if (psCurrScript->psArrayDebug[i].pIdent != NULL && strcmp(psCurrScript->psArrayDebug[i].pIdent, pIdent) == 0) { *pIndex = i; return TRUE; } } return FALSE; } // Load a script value file BOOL scrvLoad(char *pData, UDWORD size) { scrvSetInputBuffer(pData, size); if (scrv_parse() != 0) { return FALSE; } return TRUE; } /* A simple error reporting routine */ void scrv_error(char *pMessage,...) { int line; char *pText; char aTxtBuf[1024]; va_list args; va_start(args, pMessage); vsprintf(aTxtBuf, pMessage, args); scrvGetErrorData(&line, &pText); debug(LOG_ERROR, "VLO parse error: %s at line %d, token: %d, text: '%s'", aTxtBuf, line, scrv_char, pText); va_end(args); }