/* 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 "objectives.h" static int fireObjectivesComplete; void doObjectives(void) { int objectiveFailed; int hasHidden; Objective *o; battle.numObjectivesComplete = battle.numObjectivesTotal = battle.numConditions = 0; objectiveFailed = 0; hasHidden = 0; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->active) { if (!o->isCondition) { battle.numObjectivesTotal++; } else { battle.numConditions++; } if (o->isEliminateAll && o->status != OS_COMPLETE && !battle.hasThreats) { addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); o->currentValue = o->targetValue; o->status = OS_COMPLETE; runScriptFunction("OBJECTIVES_COMPLETE %d", battle.numObjectivesComplete + 1); playSound(SND_OBJECTIVE_COMPLETE); } } else { hasHidden = 1; } if (o->currentValue == o->targetValue) { switch (o->status) { case OS_COMPLETE: battle.numObjectivesComplete++; break; case OS_FAILED: objectiveFailed = 1; break; } } } if (battle.status == MS_IN_PROGRESS) { if (!hasHidden && battle.numObjectivesTotal > 0 && battle.numObjectivesComplete == battle.numObjectivesTotal) { if (fireObjectivesComplete) { fireObjectivesComplete = 0; runScriptFunction("ALL_OBJECTIVES_COMPLETE"); } if (!battle.manualComplete) { completeMission(); } } if (objectiveFailed) { failMission(); } } } void updateObjective(char *name, int type) { Objective *o; int completed, hasHidden; if (strlen(name)) { completed = battle.numObjectivesComplete; hasHidden = 0; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->active && o->status != OS_COMPLETE) { if (!o->isEliminateAll && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) { o->currentValue++; if (!o->hideNumbers) { if (o->targetValue - o->currentValue <= 10) { addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); } else if (o->currentValue % 10 == 0) { addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); } } if (o->currentValue == o->targetValue) { addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); runScriptFunction(o->description); o->status = OS_COMPLETE; runScriptFunction("OBJECTIVES_COMPLETE %d", ++completed); playSound(SND_OBJECTIVE_COMPLETE); } } } if (!o->active) { hasHidden = 1; } } if (completed == battle.numObjectivesTotal && !hasHidden && fireObjectivesComplete) { fireObjectivesComplete = 0; runScriptFunction("ALL_OBJECTIVES_COMPLETE"); } } } void adjustObjectiveTargetValue(char *name, int type, int amount) { Objective *o; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->active && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) { o->targetValue += amount; o->currentValue = MIN(o->currentValue, o->targetValue); if (o->currentValue >= o->targetValue && o->targetValue > 0) { o->status = OS_COMPLETE; addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); playSound(SND_OBJECTIVE_COMPLETE); } } } } void updateCondition(char *name, int type) { Objective *o; if (strlen(name)) { for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->active && o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) { o->currentValue++; if (o->currentValue == o->targetValue) { o->status = OS_FAILED; addHudMessage(colors.red, _("%s - Objective Failed!"), o->description); playSound(SND_OBJECTIVE_FAILED); } else if (!o->hideNumbers) { addHudMessage(colors.red, "%s - %d / %d", o->description, o->currentValue, o->targetValue); } } } } } void completeAllObjectives(void) { Objective *o; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { o->status = OS_COMPLETE; } } void completeConditions(void) { Objective *o; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->isCondition) { o->currentValue = o->targetValue; o->status = OS_COMPLETE; } } } void failIncompleteObjectives(void) { Objective *o; for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (o->status != OS_COMPLETE) { o->status = OS_FAILED; } } } void activateObjectives(char *objectives) { char *token; Objective *o; int activated; activated = 0; token = strtok(objectives, ";"); while (token) { for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { if (strcmp(token, o->id) == 0) { addHudMessage(colors.cyan, _("New Objective : %s"), o->description); o->active = 1; /* prevent race condition */ doObjectives(); if (o->isEliminateAll) { updateObjective(o->targetName, o->targetType); } activated = 1; } } token = strtok(NULL, ";"); } if (activated) { playSound(SND_NEW_OBJECTIVE); } } void loadObjectives(cJSON *node) { Objective *o; if (node) { node = node->child; while (node) { o = malloc(sizeof(Objective)); memset(o, 0, sizeof(Objective)); battle.objectiveTail->next = o; battle.objectiveTail = o; STRNCPY(o->id, cJSON_GetObjectItem(node, "description")->valuestring, MAX_DESCRIPTION_LENGTH); STRNCPY(o->description, _(cJSON_GetObjectItem(node, "description")->valuestring), MAX_DESCRIPTION_LENGTH); STRNCPY(o->targetName, cJSON_GetObjectItem(node, "targetName")->valuestring, MAX_NAME_LENGTH); o->targetValue = cJSON_GetObjectItem(node, "targetValue")->valueint; o->targetType = lookup(cJSON_GetObjectItem(node, "targetType")->valuestring); o->active = getJSONValue(node, "active", 1); o->isCondition = getJSONValue(node, "isCondition", 0); o->isEliminateAll = getJSONValue(node, "isEliminateAll", 0); o->hideNumbers = getJSONValue(node, "hideNumbers", o->isCondition); if (o->isEliminateAll) { o->targetValue = 1; } node = node->next; } } fireObjectivesComplete = 1; } void addEpicLivesObjective(void) { Objective *o; char id[MAX_DESCRIPTION_LENGTH]; o = malloc(sizeof(Objective)); memset(o, 0, sizeof(Objective)); battle.objectiveTail->next = o; battle.objectiveTail = o; sprintf(id, _("Do not lose more than %d pilots"), battle.epicLives); STRNCPY(o->id, id, MAX_DESCRIPTION_LENGTH); STRNCPY(o->description, id, MAX_DESCRIPTION_LENGTH); STRNCPY(o->targetName, "PLAYER", MAX_NAME_LENGTH); o->targetValue = battle.epicLives; o->targetType = TT_DESTROY; o->active = 1; o->isCondition = 1; } void addEpicKillsObjective(void) { Objective *o; char id[MAX_DESCRIPTION_LENGTH]; o = malloc(sizeof(Objective)); memset(o, 0, sizeof(Objective)); battle.objectiveTail->next = o; battle.objectiveTail = o; sprintf(id, _("Destroy at least %d enemy fighters"), battle.epicKills); STRNCPY(o->id, id, MAX_DESCRIPTION_LENGTH); STRNCPY(o->description, id, MAX_DESCRIPTION_LENGTH); STRNCPY(o->targetName, "EPIC_PLAYER_KILLS", MAX_NAME_LENGTH); o->targetValue = battle.epicKills; o->targetType = TT_DESTROY; o->active = 1; }