/* Copyright (C) 2015-2019 Parallel Realities This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "script.h" static void executeNextLine(ScriptRunner *runner); void destroyScript(void); static cJSON *scriptJSON, *rootJSON; static ScriptRunner head; static ScriptRunner *tail; static int runScript; void initScript(cJSON *root) { cJSON *function; memset(&head, 0, sizeof(ScriptRunner)); tail = &head; rootJSON = root; runScript = 0; scriptJSON = cJSON_GetObjectItem(root, "script"); if (scriptJSON) { function = scriptJSON->child; while (function) { SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Found script function: '%s'", cJSON_GetObjectItem(function, "function")->valuestring); function = function->next; } runScript = 1; } } void doScript(void) { ScriptRunner *runner, *prev; if (runScript) { prev = &head; for (runner = head.next ; runner != NULL ; runner = runner->next) { runner->delay = MAX(0, runner->delay - 1); if (runner->waitForMessageBox) { runner->waitForMessageBox = showingMessageBoxes(); } if (!runner->delay && !runner->waitForMessageBox) { executeNextLine(runner); if (!runner->line) { if (runner == tail) { tail = prev; } prev->next = runner->next; free(runner); runner = prev; } } prev = runner; } } } void runScriptFunction(const char *format, ...) { ScriptRunner *scriptRunner; cJSON *function; char *functionName; char funcNameBuffer[MAX_NAME_LENGTH]; va_list args; if (scriptJSON && runScript) { memset(&funcNameBuffer, '\0', sizeof(funcNameBuffer)); va_start(args, format); vsprintf(funcNameBuffer, format, args); va_end(args); function = scriptJSON->child; while (function) { functionName = cJSON_GetObjectItem(function, "function")->valuestring; if (strcmp(functionName, funcNameBuffer) == 0) { scriptRunner = malloc(sizeof(ScriptRunner)); memset(scriptRunner, 0, sizeof(ScriptRunner)); scriptRunner->line = cJSON_GetObjectItem(function, "lines")->child; tail->next = scriptRunner; tail = scriptRunner; SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Running script '%s'", funcNameBuffer); return; } function = function->next; } } } static void executeNextLine(ScriptRunner *runner) { char *line; char command[32]; char strParam[3][256]; int intParam[2]; line = runner->line->valuestring; sscanf(line, "%s", command); if (strcmp(command, "ACTIVATE_ENTITIES") == 0) { sscanf(line, "%*s %[^\n]", strParam[0]); activateEntities(strParam[0]); } else if (strcmp(command, "ACTIVATE_ENTITY_GROUPS") == 0) { sscanf(line, "%*s %[^\n]", strParam[0]); activateEntityGroups(strParam[0]); } else if (strcmp(command, "ACTIVATE_OBJECTIVES") == 0) { sscanf(line, "%*s %[^\n]", strParam[0]); activateObjectives(strParam[0]); } else if (strcmp(command, "ACTIVATE_LOCATION") == 0) { sscanf(line, "%*s %[^\n]", strParam[0]); activateLocations(strParam[0]); } else if (strcmp(command, "ACTIVATE_JUMPGATE") == 0) { sscanf(line, "%*s %d", &intParam[0]); activateJumpgate(intParam[0]); } else if (strcmp(command, "ACTIVATE_NEXT_WAYPOINT") == 0) { activateNextWaypoint(); } else if (strcmp(command, "ACTIVATE_SPAWNER") == 0) { sscanf(line, "%*s %d %[^\n]", &intParam[0], strParam[0]); activateSpawner(strParam[0], intParam[0]); } else if (strcmp(command, "MSG_BOX") == 0) { sscanf(line, "%*s %255[^;]%*c%255[^\n]", strParam[0], strParam[1]); addMessageBox(strParam[0], _(strParam[1]), MB_NORMAL); } else if (strcmp(command, "IMPORTANT_MSG_BOX") == 0) { sscanf(line, "%*s %255[^;]%*c%255[^\n]", strParam[0], strParam[1]); addMessageBox(strParam[0], _(strParam[1]), MB_IMPORTANT); } else if (strcmp(command, "PANDORAN_MSG_BOX") == 0) { sscanf(line, "%*s %255[^;]%*c%255[^\n]", strParam[0], strParam[1]); addMessageBox(strParam[0], strParam[1], MB_PANDORAN); } else if (strcmp(command, "WAIT") == 0) { sscanf(line, "%*s %d", &intParam[0]); runner->delay = intParam[0] * FPS; } else if (strcmp(command, "WAIT_MSG_BOX") == 0) { runner->waitForMessageBox = 1; } else if (strcmp(command, "COMPLETE_MISSION") == 0) { addHudMessage(colors.green, _("Mission Complete!")); completeAllObjectives(); completeMission(); } else if (strcmp(command, "END_MISSION") == 0) { battle.unwinnable = 1; completeMission(); battle.missionFinishedTimer = -FPS * 999; } else if (strcmp(command, "FAIL_MISSION") == 0) { addHudMessage(colors.red, _("Mission Failed!")); failMission(); } else if (strcmp(command, "FAIL_CHALLENGE") == 0) { addHudMessage(colors.red, _("Challenge Failed!")); failMission(); } else if (strcmp(command, "END_CHALLENGE") == 0) { battle.scriptedEnd = 1; } else if (strcmp(command, "RETREAT_ALLIES") == 0) { battle.isEpic = 0; retreatAllies(); } else if (strcmp(command, "RETREAT_ENEMIES") == 0) { battle.isEpic = 0; retreatEnemies(); } else if (strcmp(command, "CREATE_CRISTABEL_LOCATION") == 0) { createChristabelLocation(); } else if (strcmp(command, "KILL_ENTITY") == 0) { sscanf(line, "%*s %[^\n]", strParam[0]); killEntity(strParam[0]); } else if (strcmp(command, "UPDATE_ENTITY_SIDE") == 0) { sscanf(line, "%*s %s %[^\n]", strParam[0], strParam[1]); updateEntitySide(strParam[0], strParam[1]); } else if (strcmp(command, "ACTIVATE_TRESPASSER_SPAWNER") == 0) { activateTrespasserSpawner(); } else if (strcmp(command, "STOP_SCRIPT") == 0) { runScript = 0; } else if (strcmp(command, "DESTROY_TORELLI") == 0) { battle.destroyTorelli = 1; } else if (strcmp(command, "END_CAMPAIGN") == 0) { battle.campaignFinished = 1; } else { SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "ERROR: Unrecognised script command '%s'\n", command); SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "ERROR: Offending line: '%s'\n", line); } runner->line = runner->line->next; } void cancelScript(void) { ScriptRunner *runner; while (head.next) { runner = head.next; head.next = runner->next; free(runner); } tail = &head; } void destroyScript(void) { ScriptRunner *scriptRunner; if (rootJSON) { cJSON_Delete(rootJSON); rootJSON = NULL; } while (head.next) { scriptRunner = head.next; head.next = scriptRunner->next; free(scriptRunner); } tail = &head; scriptJSON = NULL; }