#include "terminals.h" #include <stdlib.h>#include "util.h"#include "datatypes.h"#include "mazes.h"#include "parse.h"#include "audio.h"#include "gui.h" /*Copyright (c) 2013-2021 Devine Lu Linvega2018 web port by rezmason2021 C89 port by rezmason Permission to use, copy, modify, and distribute this software for anypurpose with or without fee is hereby granted, provided that the abovecopyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIESWITH REGARD TO THIS SOFTWARE.*/ static Terminal (*terminals)[] = NULL;static int numTerminals;static int _isOpen = 0; static voidsetupAudio(TerminalData *data, int *isOpen, GameState *state){ NodeModifier modifier = state->audio ? MODIFIER_ON : MODIFIER_NONE; double fadeDelay = state->audio ? 0.1 : 0; (void)data; (void)isOpen; GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.3, fadeDelay); GUI_ShowAudio(state->audio);} static intchangeAudio(TerminalData *data, int *isOpen, GameState *state){ (void)isOpen; state->audio = !state->audio; Audio_SetActive(state->audio); setupAudio(data, isOpen, state); return 1;} static voidsetupProgress(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; GUI_ShowProgressScreen(state->chapter);} static voidupdateClock(GameState *state, int refresh){ GUI_ShowClockFace(state->clock, refresh); GUI_ShowClock(state->clock);} static voidsetupClock(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; updateClock(state, 0); Audio_PlayEffect(EFFECT_ACTION_ENERGY_INIT);} static intchangeClock(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; state->clock = (state->clock + 1) % 3; updateClock(state, 1); Audio_PlayEffect(EFFECT_ACTION_ENERGY_ACTIVE); return 1;} static voidupdateSeal(TerminalData *data, GameState *state){ int i, numSeals = 0, hasSeal = 0; double fadeDuration = 0.2, fadeDelay = 0.2; NodeModifier modifier = MODIFIER_NONE; GUI_ShowSeals(state->seals[0], state->seals[1]); /* Look to see how many seals the player has, and if they have this one, what index it's at */ for(i = 0; i < 2; i++) { if(state->seals[i] == data->seal) { hasSeal = 1; } if(state->seals[i] != ZONE_NONE) { numSeals++; } } if(hasSeal) { modifier = numSeals == 2 ? MODIFIER_SEAL_2 : MODIFIER_SEAL_1; fadeDuration = 0.1; fadeDelay = 0.1; } GUI_ShowNode(state->nodeName, state->orientation, modifier, fadeDuration, fadeDelay);} static voidsetupSeal(TerminalData *data, int *isOpen, GameState *state){ (void)isOpen; updateSeal(data, state); Audio_PlayEffect(EFFECT_ACTION_SEAL_INIT);} static intchangeSeal(TerminalData *data, int *isOpen, GameState *state){ int i, filledIndex = -1, emptyIndex = -1; (void)isOpen; /* Look to see what, if any, empty seal slot the player has, and if they have this seal, what index it's at */ for(i = 0; i < 2; i++) { if(emptyIndex == -1 && state->seals[i] == ZONE_NONE) { emptyIndex = i; } if(filledIndex == -1 && state->seals[i] == data->seal) { filledIndex = i; break; } } if(filledIndex != -1) { Audio_PlayEffect(EFFECT_ACTION_SEAL_INACTIVE); state->seals[filledIndex] = ZONE_NONE; } else if(emptyIndex != -1) { Audio_PlayEffect(EFFECT_ACTION_SEAL_ACTIVE); state->seals[emptyIndex] = data->seal; } else { Audio_PlayEffect(EFFECT_ACTION_ENERGY_STACK); GUI_ShowSealAlert(); } updateSeal(data, state); return 1;} static voidupdateEnergy(TerminalData *data, int *isOpen, GameState *state){ NodeModifier modifier = MODIFIER_NONE; int holdsFuse = 0; GUI_ShowEnergy(state->energy); if(*isOpen) { /* Find out whether this terminal is filled, aka whether this terminal is listed in the state's list of terminal locations */ int i, filled = 0; for(i = 0; i < 3; i++) { if(strcmp(state->fuseLocationNames[i], data->energyTerminalData.fuseName) == 0) { filled = 1; break; } } modifier = filled ? MODIFIER_ENERGY_FILLED : MODIFIER_ENERGY_EMPTY; holdsFuse = !filled && state->energy > 0; } GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.1, 0); GUI_EnableFuseCursor(holdsFuse);} static voidsetupEnergy(TerminalData *data, int *isOpen, GameState *state){ *isOpen = 0; updateEnergy(data, isOpen, state); Audio_PlayEffect(EFFECT_ACTION_ENERGY_INIT);} static intchangeEnergy(TerminalData *data, int *isOpen, GameState *state){ int success = 1; if(!*isOpen) { *isOpen = 1; } else { int i, filledIndex = -1, emptyIndex = -1; /* Look to see what, if any, empty fuse location slot the player has, and if they have this fuse, what index it's at */ for(i = 0; i < 3; i++) { if(filledIndex == -1 && strcmp(state->fuseLocationNames[i], data->energyTerminalData.fuseName) == 0) { filledIndex = i; } else if(emptyIndex == -1 && strcmp(state->fuseLocationNames[i], "") == 0) { emptyIndex = i; } } if(filledIndex != -1) { strcpy(state->fuseLocationNames[filledIndex], ""); state->energy++; } else if(state->energy > 0 && emptyIndex != -1) { strcpy(state->fuseLocationNames[emptyIndex], data->energyTerminalData.fuseName); state->energy--; } else { GUI_ShowEnergy(state->energy); GUI_ShowEnergyAlert(); success = 0; } } if(success) { updateEnergy(data, isOpen, state); } return success;} static voidresetEnergy(TerminalData *data, GameState *state){ int i; if(!data->energyTerminalData.isFilledAtStart) { return; } /* Fill the first empty fuse location slot in the state with the name of this terminal */ for(i = 0; i < 3; i++) { if(strcmp(state->fuseLocationNames[i], "") == 0) { strcpy(state->fuseLocationNames[i], data->energyTerminalData.fuseName); break; } }} static voidfindStudioSeals(TerminalData *data, GameState *state, int *hasSeal1, int *hasSeal2){ /* Look to see whether the player state lists both seals */ int i; for(i = 0; i < 2; i++) { if(state->seals[i] == data->sealLock[0]) { *hasSeal1 = 1; } if(state->seals[i] == data->sealLock[1]) { *hasSeal2 = 1; } }} static voidupdateStudio(TerminalData *data, GameState *state){ NodeModifier modifier = MODIFIER_NONE; if(state->studio) { modifier = MODIFIER_STUDIO_UNLOCKED; } else { int hasSeal1 = 0, hasSeal2 = 0; findStudioSeals(data, state, &hasSeal1, &hasSeal2); if(hasSeal1 && hasSeal2) { modifier = MODIFIER_STUDIO_SEAL_BOTH; } else if(hasSeal1) { modifier = MODIFIER_STUDIO_SEAL_1; } else if(hasSeal2) { modifier = MODIFIER_STUDIO_SEAL_2; } } GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.1, 0.1);} static voidsetupStudio(TerminalData *data, int *isOpen, GameState *state){ (void)isOpen; updateStudio(data, state); Audio_PlayEffect(EFFECT_ACTION_DOOR_INIT);} static intchangeStudio(TerminalData *data, int *isOpen, GameState *state){ int hasSeal1 = 0, hasSeal2 = 0; (void)isOpen; if(state->studio) { return 0; } findStudioSeals(data, state, &hasSeal1, &hasSeal2); if(hasSeal1 && hasSeal2) { state->studio = 1; updateStudio(data, state); Audio_PlayEffect(EFFECT_ACTION_ENERGY_ACTIVE); return 1; } return 0;} static voidsetupEntente(TerminalData *data, int *isOpen, GameState *state){ (void)isOpen; GUI_ShowMazeInstruction(data->axis, Mazes_GetInstruction(data->axis, state));} static voidsetupEntenteProgress(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; (void)state; GUI_ShowEntenteScreen();} static intchangeEndgame(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; state->completed = 1; return 1;} static voidsetupSecret(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; if(state->secret) { GUI_ShowNode(state->nodeName, state->orientation, MODIFIER_ON, 0.3, 0.1); } else { GUI_ShowNode(state->nodeName, state->orientation, MODIFIER_NONE, 0, 0); }} static intchangeSecret(TerminalData *data, int *isOpen, GameState *state){ state->secret = !state->secret; setupSecret(data, isOpen, state); return 1;} static voidnothing(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; (void)state;} static intchangeNothing(TerminalData *data, int *isOpen, GameState *state){ (void)data; (void)isOpen; (void)state; return 1;} static voidresetNothing(TerminalData *data, GameState *state){ (void)data; (void)state;} static voidparseTerminal(Terminal *terminal, char *line, int lineNumber){ int missing = 0; char name[40] = "", type[30] = ""; char params[200]; int numFound; strcpy(name, ""); strcpy(type, ""); strcpy(params, ""); /* example: type("name", params); */ numFound = sscanf(line, "%[^(](\"%[^\"]\", %[^)]);", type, name, params); if(numFound < 3) { printf("Terminal data error: only %d terms matched on line %d: %s\n", numFound, lineNumber, line); sprintf(name, "BROKEN_%d", lineNumber); } strcpy(terminal->name, name); terminal->setup = nothing; terminal->change = changeNothing; terminal->reset = resetNothing; if(strcmp(type, "audioTerminal") == 0) { terminal->setup = setupAudio; terminal->change = changeAudio; } else if(strcmp(type, "progressTerminal") == 0) { terminal->setup = setupProgress; } else if(strcmp(type, "clockTerminal") == 0) { terminal->setup = setupClock; terminal->change = changeClock; } else if(strcmp(type, "sealTerminal") == 0) { /* example: ANTECHANNEL */ char sealName[20]; strcpy(sealName, ""); missing = 1 - sscanf(params, "%[A-Z]", sealName); parseZone(&terminal->data.seal, sealName); terminal->setup = setupSeal; terminal->change = changeSeal; } else if(strcmp(type, "energyTerminal") == 0) { /* example: 1 */ missing = 1 - sscanf(params, "%d", &terminal->data.energyTerminalData.isFilledAtStart); strcpy(terminal->data.energyTerminalData.fuseName, name); terminal->setup = setupEnergy; terminal->change = changeEnergy; terminal->reset = resetEnergy; } else if(strcmp(type, "studioTerminal") == 0) { /* example: {FOREST, RAINRE} */ char sealNames[2][20]; strcpy(sealNames[0], "NONE"); strcpy(sealNames[1], "NONE"); missing = 2 - sscanf(params, "{%[^,], %[^}]", sealNames[0], sealNames[1]); parseZone(&terminal->data.sealLock[0], sealNames[0]); parseZone(&terminal->data.sealLock[1], sealNames[1]); terminal->setup = setupStudio; terminal->change = changeStudio; } else if(strcmp(type, "ententeTerminal") == 0) { /* example: X */ char axisName[5]; strcpy(axisName, ""); missing = 1 - sscanf(params, "%s", axisName); parseMazeAxis(&terminal->data.axis, axisName); terminal->setup = setupEntente; } else if(strcmp(type, "ententeProgressTerminal") == 0) { terminal->setup = setupEntenteProgress; } else if(strcmp(type, "secretTerminal") == 0) { terminal->setup = setupSecret; terminal->change = changeSecret; } else if(strcmp(type, "endgame") == 0) { terminal->change = changeEndgame; } else { printf("Terminal data error: unknown terminal type on line %d: %s\n", lineNumber, type); } if(missing > 0) { printf("Terminal data error: missing %d params on line %d: %s\n", missing, lineNumber, line); }} intTerminals_Init(char *data){ const char *lineDelim = "\n"; char *lineSave = NULL; int i = 0, lineNumber = 1; char *line; if(terminals != NULL) { printf("Terminal data error: the terminals were already initialized.\n"); return 0; } numTerminals = getNumLines(data); terminals = calloc(numTerminals, sizeof(Terminal)); line = getNextToken(data, lineDelim, &lineSave); while(line != NULL) { parseTerminal(&(*terminals)[i], line, lineNumber); line = getNextToken(NULL, lineDelim, &lineSave); lineNumber++; i++; } Lines 1–500 of 552. Load more
#include "terminals.h" #include <stdlib.h> #include "util.h" #include "datatypes.h" #include "mazes.h" #include "parse.h" #include "audio.h" #include "gui.h" /* Copyright (c) 2013-2021 Devine Lu Linvega 2018 web port by rezmason 2021 C89 port by rezmason Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ static Terminal (*terminals)[] = NULL; static int numTerminals; static int _isOpen = 0; static void setupAudio(TerminalData *data, int *isOpen, GameState *state) { NodeModifier modifier = state->audio ? MODIFIER_ON : MODIFIER_NONE; double fadeDelay = state->audio ? 0.1 : 0; (void)data; (void)isOpen; GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.3, fadeDelay); GUI_ShowAudio(state->audio); } static int changeAudio(TerminalData *data, int *isOpen, GameState *state) { (void)isOpen; state->audio = !state->audio; Audio_SetActive(state->audio); setupAudio(data, isOpen, state); return 1; } static void setupProgress(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; GUI_ShowProgressScreen(state->chapter); } static void updateClock(GameState *state, int refresh) { GUI_ShowClockFace(state->clock, refresh); GUI_ShowClock(state->clock); } static void setupClock(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; updateClock(state, 0); Audio_PlayEffect(EFFECT_ACTION_ENERGY_INIT); } static int changeClock(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; state->clock = (state->clock + 1) % 3; updateClock(state, 1); Audio_PlayEffect(EFFECT_ACTION_ENERGY_ACTIVE); return 1; } static void updateSeal(TerminalData *data, GameState *state) { int i, numSeals = 0, hasSeal = 0; double fadeDuration = 0.2, fadeDelay = 0.2; NodeModifier modifier = MODIFIER_NONE; GUI_ShowSeals(state->seals[0], state->seals[1]); /* Look to see how many seals the player has, and if they have this one, what index it's at */ for(i = 0; i < 2; i++) { if(state->seals[i] == data->seal) { hasSeal = 1; } if(state->seals[i] != ZONE_NONE) { numSeals++; } } if(hasSeal) { modifier = numSeals == 2 ? MODIFIER_SEAL_2 : MODIFIER_SEAL_1; fadeDuration = 0.1; fadeDelay = 0.1; } GUI_ShowNode(state->nodeName, state->orientation, modifier, fadeDuration, fadeDelay); } static void setupSeal(TerminalData *data, int *isOpen, GameState *state) { (void)isOpen; updateSeal(data, state); Audio_PlayEffect(EFFECT_ACTION_SEAL_INIT); } static int changeSeal(TerminalData *data, int *isOpen, GameState *state) { int i, filledIndex = -1, emptyIndex = -1; (void)isOpen; /* Look to see what, if any, empty seal slot the player has, and if they have this seal, what index it's at */ for(i = 0; i < 2; i++) { if(emptyIndex == -1 && state->seals[i] == ZONE_NONE) { emptyIndex = i; } if(filledIndex == -1 && state->seals[i] == data->seal) { filledIndex = i; break; } } if(filledIndex != -1) { Audio_PlayEffect(EFFECT_ACTION_SEAL_INACTIVE); state->seals[filledIndex] = ZONE_NONE; } else if(emptyIndex != -1) { Audio_PlayEffect(EFFECT_ACTION_SEAL_ACTIVE); state->seals[emptyIndex] = data->seal; } else { Audio_PlayEffect(EFFECT_ACTION_ENERGY_STACK); GUI_ShowSealAlert(); } updateSeal(data, state); return 1; } static void updateEnergy(TerminalData *data, int *isOpen, GameState *state) { NodeModifier modifier = MODIFIER_NONE; int holdsFuse = 0; GUI_ShowEnergy(state->energy); if(*isOpen) { /* Find out whether this terminal is filled, aka whether this terminal is listed in the state's list of terminal locations */ int i, filled = 0; for(i = 0; i < 3; i++) { if(strcmp(state->fuseLocationNames[i], data->energyTerminalData.fuseName) == 0) { filled = 1; break; } } modifier = filled ? MODIFIER_ENERGY_FILLED : MODIFIER_ENERGY_EMPTY; holdsFuse = !filled && state->energy > 0; } GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.1, 0); GUI_EnableFuseCursor(holdsFuse); } static void setupEnergy(TerminalData *data, int *isOpen, GameState *state) { *isOpen = 0; updateEnergy(data, isOpen, state); Audio_PlayEffect(EFFECT_ACTION_ENERGY_INIT); } static int changeEnergy(TerminalData *data, int *isOpen, GameState *state) { int success = 1; if(!*isOpen) { *isOpen = 1; } else { int i, filledIndex = -1, emptyIndex = -1; /* Look to see what, if any, empty fuse location slot the player has, and if they have this fuse, what index it's at */ for(i = 0; i < 3; i++) { if(filledIndex == -1 && strcmp(state->fuseLocationNames[i], data->energyTerminalData.fuseName) == 0) { filledIndex = i; } else if(emptyIndex == -1 && strcmp(state->fuseLocationNames[i], "") == 0) { emptyIndex = i; } } if(filledIndex != -1) { strcpy(state->fuseLocationNames[filledIndex], ""); state->energy++; } else if(state->energy > 0 && emptyIndex != -1) { strcpy(state->fuseLocationNames[emptyIndex], data->energyTerminalData.fuseName); state->energy--; } else { GUI_ShowEnergy(state->energy); GUI_ShowEnergyAlert(); success = 0; } } if(success) { updateEnergy(data, isOpen, state); } return success; } static void resetEnergy(TerminalData *data, GameState *state) { int i; if(!data->energyTerminalData.isFilledAtStart) { return; } /* Fill the first empty fuse location slot in the state with the name of this terminal */ for(i = 0; i < 3; i++) { if(strcmp(state->fuseLocationNames[i], "") == 0) { strcpy(state->fuseLocationNames[i], data->energyTerminalData.fuseName); break; } } } static void findStudioSeals(TerminalData *data, GameState *state, int *hasSeal1, int *hasSeal2) { /* Look to see whether the player state lists both seals */ int i; for(i = 0; i < 2; i++) { if(state->seals[i] == data->sealLock[0]) { *hasSeal1 = 1; } if(state->seals[i] == data->sealLock[1]) { *hasSeal2 = 1; } } } static void updateStudio(TerminalData *data, GameState *state) { NodeModifier modifier = MODIFIER_NONE; if(state->studio) { modifier = MODIFIER_STUDIO_UNLOCKED; } else { int hasSeal1 = 0, hasSeal2 = 0; findStudioSeals(data, state, &hasSeal1, &hasSeal2); if(hasSeal1 && hasSeal2) { modifier = MODIFIER_STUDIO_SEAL_BOTH; } else if(hasSeal1) { modifier = MODIFIER_STUDIO_SEAL_1; } else if(hasSeal2) { modifier = MODIFIER_STUDIO_SEAL_2; } } GUI_ShowNode(state->nodeName, state->orientation, modifier, 0.1, 0.1); } static void setupStudio(TerminalData *data, int *isOpen, GameState *state) { (void)isOpen; updateStudio(data, state); Audio_PlayEffect(EFFECT_ACTION_DOOR_INIT); } static int changeStudio(TerminalData *data, int *isOpen, GameState *state) { int hasSeal1 = 0, hasSeal2 = 0; (void)isOpen; if(state->studio) { return 0; } findStudioSeals(data, state, &hasSeal1, &hasSeal2); if(hasSeal1 && hasSeal2) { state->studio = 1; updateStudio(data, state); Audio_PlayEffect(EFFECT_ACTION_ENERGY_ACTIVE); return 1; } return 0; } static void setupEntente(TerminalData *data, int *isOpen, GameState *state) { (void)isOpen; GUI_ShowMazeInstruction(data->axis, Mazes_GetInstruction(data->axis, state)); } static void setupEntenteProgress(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; (void)state; GUI_ShowEntenteScreen(); } static int changeEndgame(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; state->completed = 1; return 1; } static void setupSecret(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; if(state->secret) { GUI_ShowNode(state->nodeName, state->orientation, MODIFIER_ON, 0.3, 0.1); } else { GUI_ShowNode(state->nodeName, state->orientation, MODIFIER_NONE, 0, 0); } } static int changeSecret(TerminalData *data, int *isOpen, GameState *state) { state->secret = !state->secret; setupSecret(data, isOpen, state); return 1; } static void nothing(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; (void)state; } static int changeNothing(TerminalData *data, int *isOpen, GameState *state) { (void)data; (void)isOpen; (void)state; return 1; } static void resetNothing(TerminalData *data, GameState *state) { (void)data; (void)state; } static void parseTerminal(Terminal *terminal, char *line, int lineNumber) { int missing = 0; char name[40] = "", type[30] = ""; char params[200]; int numFound; strcpy(name, ""); strcpy(type, ""); strcpy(params, ""); /* example: type("name", params); */ numFound = sscanf(line, "%[^(](\"%[^\"]\", %[^)]);", type, name, params); if(numFound < 3) { printf("Terminal data error: only %d terms matched on line %d: %s\n", numFound, lineNumber, line); sprintf(name, "BROKEN_%d", lineNumber); } strcpy(terminal->name, name); terminal->setup = nothing; terminal->change = changeNothing; terminal->reset = resetNothing; if(strcmp(type, "audioTerminal") == 0) { terminal->setup = setupAudio; terminal->change = changeAudio; } else if(strcmp(type, "progressTerminal") == 0) { terminal->setup = setupProgress; } else if(strcmp(type, "clockTerminal") == 0) { terminal->setup = setupClock; terminal->change = changeClock; } else if(strcmp(type, "sealTerminal") == 0) { /* example: ANTECHANNEL */ char sealName[20]; strcpy(sealName, ""); missing = 1 - sscanf(params, "%[A-Z]", sealName); parseZone(&terminal->data.seal, sealName); terminal->setup = setupSeal; terminal->change = changeSeal; } else if(strcmp(type, "energyTerminal") == 0) { /* example: 1 */ missing = 1 - sscanf(params, "%d", &terminal->data.energyTerminalData.isFilledAtStart); strcpy(terminal->data.energyTerminalData.fuseName, name); terminal->setup = setupEnergy; terminal->change = changeEnergy; terminal->reset = resetEnergy; } else if(strcmp(type, "studioTerminal") == 0) { /* example: {FOREST, RAINRE} */ char sealNames[2][20]; strcpy(sealNames[0], "NONE"); strcpy(sealNames[1], "NONE"); missing = 2 - sscanf(params, "{%[^,], %[^}]", sealNames[0], sealNames[1]); parseZone(&terminal->data.sealLock[0], sealNames[0]); parseZone(&terminal->data.sealLock[1], sealNames[1]); terminal->setup = setupStudio; terminal->change = changeStudio; } else if(strcmp(type, "ententeTerminal") == 0) { /* example: X */ char axisName[5]; strcpy(axisName, ""); missing = 1 - sscanf(params, "%s", axisName); parseMazeAxis(&terminal->data.axis, axisName); terminal->setup = setupEntente; } else if(strcmp(type, "ententeProgressTerminal") == 0) { terminal->setup = setupEntenteProgress; } else if(strcmp(type, "secretTerminal") == 0) { terminal->setup = setupSecret; terminal->change = changeSecret; } else if(strcmp(type, "endgame") == 0) { terminal->change = changeEndgame; } else { printf("Terminal data error: unknown terminal type on line %d: %s\n", lineNumber, type); } if(missing > 0) { printf("Terminal data error: missing %d params on line %d: %s\n", missing, lineNumber, line); } } int Terminals_Init(char *data) { const char *lineDelim = "\n"; char *lineSave = NULL; int i = 0, lineNumber = 1; char *line; if(terminals != NULL) { printf("Terminal data error: the terminals were already initialized.\n"); return 0; } numTerminals = getNumLines(data); terminals = calloc(numTerminals, sizeof(Terminal)); line = getNextToken(data, lineDelim, &lineSave); while(line != NULL) { parseTerminal(&(*terminals)[i], line, lineNumber); line = getNextToken(NULL, lineDelim, &lineSave); lineNumber++; i++; }