void loadConfig() { FILE *fp; char settingsFile[MAX_PATH_LENGTH], *line, *savePtr; unsigned char *buffer; long length; resetGameSettings(); game.hasConfig = FALSE; snprintf(settingsFile, sizeof(settingsFile), "%sconfig", gameSavePath); resetControls(FALSE); fp = fopen(settingsFile, "rb"); if (fp == NULL) { game.firstRun = TRUE; return; } game.firstRun = FALSE; fseek(fp, 0L, SEEK_END); length = ftell(fp); buffer = malloc((length + 1) * sizeof(unsigned char)); if (buffer == NULL) { showErrorAndExit("Failed to allocate a whole %ld bytes for config file...", length); exit(1); } fseek(fp, 0L, SEEK_SET); fread(buffer, length, 1, fp); buffer[length] = '\0'; fclose(fp); savePtr = NULL; line = strtok_r((char *)buffer, "\n", &savePtr); while (line != NULL) { if (strcmpignorecase(line, "CONTROLS") == 0) { readControlsFromFile(savePtr); } else if (strcmpignorecase(line, "GAME_SETTINGS") == 0) { readGameSettingsFromFile(savePtr); } line = strtok_r(NULL, "\n", &savePtr); } game.hasConfig = TRUE; free(buffer); }
SDL_Surface *createDialogBox(char *title, char *msg) { char *text, *token, word[MAX_VALUE_LENGTH], *savePtr, *titleText; int i, lines, w, h, maxWidth, lineBreak, *lineBreaks; SDL_Surface **surface, *tempSurface; SDL_Rect dest; savePtr = NULL; freeDialogBox(); text = malloc(strlen(msg) + 1); if (text == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(msg) + 1); } STRNCPY(text, msg, strlen(msg) + 1); titleText = NULL; if (title != NULL) { titleText = malloc(strlen(title) + 1); if (titleText == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(title) + 1); } STRNCPY(titleText, title, strlen(title) + 1); } token = strtok_r(text, " ", &savePtr); i = 0; while (token != NULL) { i++; token = strtok_r(NULL, " ", &savePtr); } lines = i; if (titleText != NULL) { token = titleText; while (*token != '\0') { if (*token == '_') { *token = ' '; } token++; } lines++; } surface = malloc(sizeof(SDL_Surface *) * lines); if (surface == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Surfaces", (int)sizeof(SDL_Surface *) * lines); } lineBreaks = malloc(sizeof(int) * lines); if (lineBreaks == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the line breaks", (int)sizeof(int) * lines); } STRNCPY(text, msg, strlen(msg) + 1); token = strtok_r(text, " ", &savePtr); i = 0; maxWidth = w = h = 0; if (titleText != NULL) { surface[i] = generateTextSurface(titleText, game.font, 255, 255, 0, 0, 0, 0); h = surface[i]->h + 5; maxWidth = surface[i]->w; i++; } while (token != NULL) { lineBreak = FALSE; snprintf(word, sizeof(word), "%d", game.kills); token = replaceString(token, "[GAME_KILLS]", word); token = replaceString(token, "[HOURS]", getPlayTimeHours()); snprintf(word, sizeof(word), "%d", game.continues); token = replaceString(token, "[CONTINUE_COUNT]", word); token = replaceString(token, "[INPUT_LEFT]", getKeyValue(control.button[CONTROL_LEFT])); token = replaceString(token, "[INPUT_RIGHT]", getKeyValue(control.button[CONTROL_RIGHT])); token = replaceString(token, "[INPUT_JUMP]", getKeyValue(control.button[CONTROL_JUMP])); token = replaceString(token, "[INPUT_BLOCK]", getKeyValue(control.button[CONTROL_BLOCK])); token = replaceString(token, "[INPUT_ATTACK]", getKeyValue(control.button[CONTROL_ATTACK])); token = replaceString(token, "[INPUT_INTERACT]", getKeyValue(control.button[CONTROL_INTERACT])); token = replaceString(token, "[INPUT_ACTIVATE]", getKeyValue(control.button[CONTROL_ACTIVATE])); token = replaceString(token, "[INPUT_INVENTORY]", getKeyValue(control.button[CONTROL_INVENTORY])); token = replaceString(token, "[INPUT_PREVIOUS]", getKeyValue(control.button[CONTROL_PREVIOUS])); token = replaceString(token, "[INPUT_NEXT]", getKeyValue(control.button[CONTROL_NEXT])); snprintf(word, sizeof(word), "%s ", token); if (word[strlen(word) - 2] == '\n') { lineBreak = TRUE; word[strlen(word) - 2] = '\0'; } token = strtok_r(NULL, " ", &savePtr); if (token == NULL) { word[strlen(word) - 1] = '\0'; } surface[i] = generateTextSurface(word, game.font, 255, 255, 255, 0, 0, 0); lineBreaks[i] = lineBreak; if (h == 0 || (i == 1 && titleText != NULL)) { h += surface[i]->h + 5; } if (w + surface[i]->w > MAX_DIALOG_WIDTH) { w = 0; h += surface[i]->h + 5; } w += surface[i]->w; if (w > maxWidth) { maxWidth = w; } if (lineBreak == TRUE) { w = 0; h += surface[i]->h + 5; } i++; } h -= 5; tempSurface = createSurface(maxWidth, h); w = h = 0; for (i=0; i<lines; i++) { if (w + surface[i]->w > MAX_DIALOG_WIDTH || (titleText != NULL && i == 1)) { w = 0; h += surface[i]->h + 5; } dest.x = w; dest.y = h; dest.w = surface[i]->w; dest.h = surface[i]->h; SDL_BlitSurface(surface[i], NULL, tempSurface, &dest); w += surface[i]->w; SDL_FreeSurface(surface[i]); if (lineBreaks[i] == TRUE) { w = 0; h += surface[i]->h + 5; } } tempSurface = addBorder(tempSurface, 255, 255, 255, 0, 0, 0); free(surface); free(text); if (titleText != NULL) { free(titleText); } free(lineBreaks); return tempSurface; }
static void changeSides() { int side; Entity *e, *smoke; Target *t; self->x += self->dirX; self->y += self->dirY; if (atTarget()) { self->flags |= NO_DRAW; self->takeDamage = NULL; self->targetX = self->x; self->dirX = 0; self->thinkTime = 120; side = prand() % 2; if (side == 0) { t = getTargetByName("SNAKE_BOSS_TARGET_LEFT"); self->face = RIGHT; } else { t = getTargetByName("SNAKE_BOSS_TARGET_RIGHT"); self->face = LEFT; } if (t == NULL) { showErrorAndExit("Snake boss cannot find target"); } self->damage = 0; setSnakePosition(t->x, t->y); self->targetX = self->x; self->targetY = self->y - 64; self->thinkTime = 120; self->action = &riseUpWait; } else { e = self->target; while (e != NULL) { if (e->target == NULL) { smoke = addSmoke(e->x + (prand() % self->w) * (prand() % 2 == 0 ? -1 : 1), e->y + prand() % e->h, "decoration/dust"); if (smoke != NULL) { smoke->dirY = 0; } } e = e->target; } } alignBodyToHead(); }
static void eatExplode() { int i; Entity *e; Target *t; self->maxThinkTime = 0; t = getCenterTarget(); self->startX = 0; for (i=0;i<60;i++) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add a Blob Boss Part"); } loadProperties("boss/blob_boss_part", e); setEntityAnimation(e, "STAND"); e->flags |= LIMIT_TO_SCREEN; e->x = self->x; e->y = self->y; e->x += prand() % self->w; e->y += prand() % (self->h - e->h); e->dirX = (10 + prand() % 20) * (prand() % 2 == 0 ? 1 : -1); e->dirX /= 10; e->dirY = -6 - prand() % 4; e->touch = &entityTouch; e->damage = 0; e->health = 600; e->action = &partWait; e->pain = &enemyPain; e->draw = &drawLoopingAnimationToMap; e->head = self; e->type = ENEMY; e->targetX = t->x; e->targetY = t->y; self->startX++; } self->target = NULL; self->thinkTime = 120; self->action = &explodeWait; setEntityAnimation(self, "WALK"); self->flags |= NO_DRAW; self->frameSpeed = 0; self->maxThinkTime = 1; self->touch = NULL; }
static unsigned char *uncompressFile(char *name, int writeToFile) { char *filename; unsigned long size; unsigned char *source, *dest; FILE *fp; #if DEV != 1 int i, index; #endif filename = NULL; filename = malloc(MAX_PATH_LENGTH); if (filename == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for filename", MAX_PATH_LENGTH); } #if DEV == 1 fp = fopen(name, "rb"); if (fp == NULL) { showErrorAndExit("Failed to open %s", name); } fseek(fp, 0L, SEEK_END); size = ftell(fp); fseek(fp, 0L, SEEK_SET); dest = malloc((size + 2) * sizeof(unsigned char)); if (dest == NULL) { showErrorAndExit("Failed to allocate %ld bytes to load %s", (size + 2) * (int)sizeof(unsigned char), name); } fread(dest, size, 1, fp); dest[size] = '\n'; dest[size + 1] = '\0'; source = NULL; #else index = -1; for (i=0;i<fileCount;i++) { if (strcmpignorecase(fileData[i].filename, name) == 0) { index = i; break; } } if (index == -1) { showErrorAndExit("Failed to find %s in PAK file", name); } fp = fopen(pakFile, "rb"); if (fp == NULL) { showErrorAndExit("Failed to open PAK file %s", pakFile); } fseek(fp, fileData[index].offset, SEEK_SET); source = malloc(fileData[index].compressedSize * sizeof(unsigned char)); if (source == NULL) { showErrorAndExit("Failed to allocate %ld bytes to load %s from PAK", fileData[index].compressedSize * (int)sizeof(unsigned char), name); } dest = malloc((fileData[index].fileSize + 1) * sizeof(unsigned char)); if (dest == NULL) { showErrorAndExit("Failed to allocate %ld bytes to load %s from PAK", fileData[index].fileSize * (int)sizeof(unsigned char), name); } fread(source, fileData[index].compressedSize, 1, fp); size = fileData[index].fileSize; uncompress(dest, &size, source, fileData[index].compressedSize); dest[size] = '\0'; if (size != fileData[index].fileSize) { showErrorAndExit("Failed to decompress %s. Expected %ld, got %ld", fileData[index].filename, fileData[index].fileSize, size); } if (writeToFile == TRUE) { fclose(fp); snprintf(filename, MAX_PATH_LENGTH, "%spakdata", getGameSavePath()); printf("Writing to %s\n", filename); fp = fopen(filename, "wb"); if (fp == NULL) { showErrorAndExit("Failed to write pak data to temp file: %s", strerror(errno)); } fwrite(dest, size, 1, fp); free(dest); } #endif if (source != NULL) { free(source); } if (filename != NULL && writeToFile == FALSE) { free(filename); } fclose(fp); if (writeToFile == TRUE) { return (unsigned char *)filename; } else { return dest; } }
static void disintegrationAttack() { Entity *e; self->thinkTime--; if (self->thinkTime <= 0) { if (self->mental == 0) { self->y = getMapFloor(self->x + self->w / 2, self->y) - self->h; self->flags &= ~NO_DRAW; addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2); self->mental = 1; self->thinkTime = 30; } else { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add the Disintegration Spell"); } setEntityAnimation(self, "ATTACK_2"); loadProperties("boss/sorceror_disintegration_spell", e); setEntityAnimation(e, "STAND"); e->face = self->face; if (self->face == LEFT) { e->x = self->x + self->w - e->w - e->offsetX; } else { e->x = self->x + e->offsetX; } e->y = self->y + e->offsetY; e->action = &disintegrationSpellInit; e->thinkTime = 120; e->startX = e->x; e->startY = e->y; e->head = self; e->endX = player.x + player.w / 2; e->endY = player.y + player.h / 2; e->draw = &drawLoopingAnimationToMap; self->mental = 1; self->action = &disintegrationAttackWait; self->thinkTime = 30; } } }
static void splitAttackInit() { int i; Entity *e; Target *t; self->maxThinkTime = 0; t = getCenterTarget(); for (i=0;i<60;i++) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add a Blob Boss Part"); } loadProperties("boss/blob_boss_part", e); e->flags |= LIMIT_TO_SCREEN; setEntityAnimation(e, "WALK"); e->x = self->x; e->y = self->y; e->x += prand() % self->w; e->y += prand() % (self->h - e->h); e->dirX = (10 + prand() % 20) * (prand() % 2 == 0 ? 1 : -1); e->dirX /= 10; e->dirY = -6; e->action = &partAttack; e->touch = &partGrab; e->die = &partDie; e->pain = &enemyPain; e->draw = &drawLoopingAnimationToMap; e->takeDamage = &partTakeDamage; e->head = self; e->type = ENEMY; e->thinkTime = 60; e->targetX = t->x; e->targetY = t->y; } self->maxThinkTime = 60; self->action = &headWait; setEntityAnimation(self, "BLOCK"); self->flags |= NO_DRAW; self->frameSpeed = 0; self->touch = NULL; }
static void entityWait() { int frameCount = getFrameCount(self); Entity *e; if (self->active == TRUE) { self->thinkTime--; if (self->thinkTime % 120 == 0) { self->currentFrame++; if (self->currentFrame >= frameCount) { self->currentFrame = frameCount - 1; } } else if (self->thinkTime % 5 == 0) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add the Fire"); } loadProperties("boss/phoenix_die_fire", e); setEntityAnimation(e, "STAND"); e->x = self->x + prand() % self->w; e->y = self->y + self->h - e->h; e->action = &fireWait; e->draw = &drawLoopingAnimationToMap; e->type = ENEMY; e->flags |= DO_NOT_PERSIST|FLY; e->thinkTime = 30; e->health = 0; e->maxHealth = 3 + prand() % 3; e->mental = 1; e->head = self; } if (self->thinkTime <= 0) { self->inUse = FALSE; } } else { self->frameSpeed = 0; self->thinkTime = frameCount * 120; } checkToMap(self); }
static void loadMenuLayout() { Medal *medal; int i, width, medalCount; Texture *texture; medal = getMedals(); medalCount = getMedalCount(); i = 0; width = 0; menu.w = 0; menu.h = 0; menu.startY = 0; menu.endY = 0; menu.widgetCount = medalCount; menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount); if (menu.widgets == NULL) { showErrorAndExit("Ran out of memory when creating Medals Menu"); } for (i=0;i<menu.widgetCount;i++) { if (medal[i].hidden == TRUE && medal[i].obtained == FALSE) { menu.widgets[i] = createWidget(_("Hidden Medal"), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 255, 255, 255); } else { if (medal[i].obtained == TRUE) { menu.widgets[i] = createWidget(_(medal[i].description), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 0, 200, 0); } else { menu.widgets[i] = createWidget(_(medal[i].description), NULL, NULL, NULL, NULL, 10, 20 + i * 40, FALSE, 255, 255, 255); } } if (width < menu.widgets[i]->x + menu.widgets[i]->normalState->w) { width = menu.widgets[i]->x + menu.widgets[i]->normalState->w; } texture = getMedalImage(medal[i].medalType, medal[i].obtained); menu.widgets[i]->label = createImageLabel(texture, menu.widgets[i]->x, menu.widgets[i]->y); menu.widgets[i]->label->y = menu.widgets[i]->y + menu.widgets[i]->normalState->h / 2 - menu.widgets[i]->label->text->h / 2; menu.endY = menu.widgets[i]->y + menu.widgets[i]->normalState->h - menu.h; } width += 15; menu.h = SCREEN_HEIGHT - BUTTON_PADDING; for (i=0;i<menu.widgetCount;i++) { if (menu.widgets[i]->label != NULL) { menu.widgets[i]->label->x = width; if (menu.w < menu.widgets[i]->label->x + menu.widgets[i]->label->text->w) { menu.w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w; } } } menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0); menu.x = (SCREEN_WIDTH - menu.background->w) / 2; menu.y = (SCREEN_HEIGHT - menu.background->h) / 2; }
static SDL_Surface *createWidgetText(char *msg, TTF_Font *font, int fr, int fg, int fb, int br, int bg, int bb) { char *text, *token, word[MAX_VALUE_LENGTH], *savePtr; int i, lines, w, h, maxWidth, lineBreak, *lineBreaks; SDL_Surface **surface, *tempSurface; SDL_Rect dest; savePtr = NULL; text = malloc(strlen(msg) + 1); if (text == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Text", (int)strlen(msg) + 1); } STRNCPY(text, msg, strlen(msg) + 1); token = strtok_r(text, " ", &savePtr); i = 0; while (token != NULL) { i++; token = strtok_r(NULL, " ", &savePtr); } lines = i; surface = malloc(sizeof(SDL_Surface *) * lines); if (surface == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the Dialog Surfaces", (int)sizeof(SDL_Surface *) * lines); } lineBreaks = malloc(sizeof(int) * lines); if (lineBreaks == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for the line breaks", (int)sizeof(int) * lines); } STRNCPY(text, msg, strlen(msg) + 1); token = strtok_r(text, " ", &savePtr); i = 0; maxWidth = w = h = 0; while (token != NULL) { lineBreak = FALSE; snprintf(word, sizeof(word), "%s ", token); if (word[strlen(word) - 2] == '\n') { lineBreak = TRUE; word[strlen(word) - 2] = '\0'; } token = strtok_r(NULL, " ", &savePtr); if (token == NULL) { word[strlen(word) - 1] = '\0'; } surface[i] = generateTextSurface(word, game.font, fr, fg, fb, br, bg, bb); lineBreaks[i] = lineBreak; if (h == 0) { h += surface[i]->h + 5; } if (w + surface[i]->w > MAX_SCRIPT_WIDTH) { w = 0; h += surface[i]->h + 5; } w += surface[i]->w; if (w > maxWidth) { maxWidth = w; } if (lineBreak == TRUE) { w = 0; h += surface[i]->h + 5; } i++; } h -= 5; tempSurface = createSurface(maxWidth, h); w = h = 0; for (i=0;i<lines;i++) { if (w + surface[i]->w > MAX_SCRIPT_WIDTH) { w = 0; h += surface[i]->h + 5; } dest.x = w; dest.y = h; dest.w = surface[i]->w; dest.h = surface[i]->h; SDL_BlitSurface(surface[i], NULL, tempSurface, &dest); w += surface[i]->w; SDL_FreeSurface(surface[i]); if (lineBreaks[i] == TRUE) { w = 0; h += surface[i]->h + 5; } } free(surface); free(text); free(lineBreaks); return tempSurface; }
static void summonEnemies() { char summonList[MAX_VALUE_LENGTH], enemyToSummon[MAX_VALUE_LENGTH]; char *token; int i, summonIndex = 0, summonCount = 0; Entity *e; for (i=0;i<2;i++) { summonCount = 0; summonIndex = 0; STRNCPY(summonList, self->requires, MAX_VALUE_LENGTH); token = strtok(summonList, "|"); while (token != NULL) { token = strtok(NULL, "|"); summonCount++; } if (summonCount == 0) { showErrorAndExit("Scanner at %f %f has no summon list", self->x, self->y); } summonIndex = prand() % summonCount; STRNCPY(summonList, self->requires, MAX_VALUE_LENGTH); summonCount = 0; token = strtok(summonList, "|"); while (token != NULL) { if (summonCount == summonIndex) { break; } token = strtok(NULL, "|"); summonCount++; } snprintf(enemyToSummon, MAX_VALUE_LENGTH, "enemy/%s", token); e = addEnemy(enemyToSummon, self->x, self->y); e->x = self->x; e->y = self->y; e->targetX = self->x + (i == 0 ? -64 : 64); e->targetY = self->y; calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY); e->flags |= (NO_DRAW|HELPLESS|TELEPORTING); } }
void saveTemporaryData() { char *line, itemName[MAX_MESSAGE_LENGTH], *savePtr; char swapFile[MAX_PATH_LENGTH]; char *mapName = getMapFilename(); unsigned char *buffer; int skipping = FALSE; FILE *read; FILE *write; savePtr = NULL; snprintf(swapFile, sizeof(swapFile), "%sswap", gameSavePath); read = fopen(tempFile, "rb"); write = fopen(swapFile, "wb"); if (read == NULL) { if (temporaryDataExists == TRUE) { showErrorAndExit("SAVE TEMP DATA: Could not find persistance file: %s", strerror(errno)); } } else { fclose(read); buffer = decompressFile(tempFile); if (strlen((char *)buffer) == 0) { showErrorAndExit("Something went wrong when decompressing the persistance file"); } line = strtok_r((char *)buffer, "\n", &savePtr); while (line != NULL) { if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } if (line[strlen(line) - 1] == '\r') { line[strlen(line) - 1] = '\0'; } if (skipping == FALSE) { sscanf(line, "%s", itemName); if (strcmpignorecase("PLAYER_DATA", line) == 0 || strcmpignorecase("PLAYER_INVENTORY", line) == 0 || strcmpignorecase("GLOBAL_TRIGGER", line) == 0 || strcmpignorecase("OBJECTIVE", line) == 0 || strcmpignorecase("PLAYER_LOCATION", line) == 0 || strcmpignorecase("MAP_TRIGGER", line) == 0) { skipping = TRUE; } else if (strcmpignorecase("MAP_NAME", itemName) == 0) { sscanf(line, "%*s %s\n", itemName); if (strcmpignorecase(itemName, mapName) == 0) { skipping = TRUE; } else { fprintf(write, "%s\n", line); } } else { fprintf(write, "%s\n", line); } } else { sscanf(line, "%s", itemName); if (strcmpignorecase("MAP_NAME", itemName) == 0) { sscanf(line, "%*s %s\n", itemName); if (strcmpignorecase(itemName, mapName) != 0) { skipping = FALSE; fprintf(write, "%s\n", line); } } } line = strtok_r(NULL, "\n", &savePtr); } free(buffer); if (remove(tempFile) != 0) { showErrorAndExit("Could not remove temporary file"); } } fprintf(write, "MAP_NAME %s\n", mapName); fprintf(write, "ENTITY_DATA\n"); /* Now write out all of the Entities */ writeEntitiesToFile(write); /* Now the targets */ writeTargetsToFile(write); /* And the triggers */ writeTriggersToFile(write); fclose(write); if (rename(swapFile, tempFile) != 0) { showErrorAndExit("Could not rename temporary file"); } #if DEV == 1 copyFile(tempFile, "tmpdata"); #endif compressFile(tempFile); temporaryDataExists = TRUE; }
void saveGame(int slot) { char itemName[MAX_MESSAGE_LENGTH], *line, *savePtr; char saveFile[MAX_PATH_LENGTH]; char *mapName = getMapFilename(); char tempSaveFile[MAX_PATH_LENGTH]; int i; unsigned char *buffer; int skipping = FALSE; FILE *read; FILE *write; savePtr = NULL; if (slot == -1) { for (i=1001;;i++) { snprintf(saveFile, sizeof(saveFile), "%ssave%d", gameSavePath, i); read = fopen(saveFile, "rb"); if (read == NULL) { break; } else { fclose(read); } } } else { /* Backup older save */ snprintf(saveFile, sizeof(saveFile), "%ssave%d", gameSavePath, slot); snprintf(tempSaveFile, sizeof(tempSaveFile), "%stempsave%d", gameSavePath, slot); } write = fopen(tempSaveFile, "wb"); fprintf(write, "VERSION %0.2f\n", VERSION); fprintf(write, "PLAY_TIME %ld\n", game.playTime); fprintf(write, "PLAYER_KILLS %d\n", game.kills); fprintf(write, "BATS_DROWNED %d\n", game.batsDrowned); fprintf(write, "TIMES_EATEN %d\n", game.timesEaten); fprintf(write, "DISTANCE_TRAVELLED %u\n", game.distanceTravelled); fprintf(write, "ATTACKS_BLOCKED %d\n", game.attacksBlocked); fprintf(write, "SLIME_TIME %d\n", game.timeSpentAsSlime); fprintf(write, "ARROWS_FIRED %d\n", game.arrowsFired); fprintf(write, "SECRETS_FOUND %d\n", game.secretsFound); fprintf(write, "CONTINUES %d\n", game.continues); fprintf(write, "CHEATING %d\n", game.cheating); fprintf(write, "PLAYER_LOCATION %s\n", mapName); read = fopen(tempFile, "rb"); if (read == NULL) { if (temporaryDataExists == TRUE) { showErrorAndExit("SAVE GAME: Could not find persistance file: %s", strerror(errno)); } } else { fclose(read); buffer = decompressFile(tempFile); line = strtok_r((char *)buffer, "\n", &savePtr); while (line != NULL) { if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } if (line[strlen(line) - 1] == '\r') { line[strlen(line) - 1] = '\0'; } if (skipping == FALSE) { sscanf(line, "%s", itemName); if (strcmpignorecase("PLAYER_DATA", itemName) == 0 || strcmpignorecase("PLAYER_INVENTORY", itemName) == 0 || strcmpignorecase("PLAYER_LOCATION", itemName) == 0 || strcmpignorecase("VERSION", itemName) == 0) { skipping = TRUE; } else if (strcmpignorecase("MAP_NAME", itemName) == 0) { sscanf(line, "%*s %s\n", itemName); if (strcmpignorecase(itemName, mapName) == 0) { skipping = TRUE; } else { fprintf(write, "%s\n", line); } } else { fprintf(write, "%s\n", line); } } else { sscanf(line, "%s", itemName); if (strcmpignorecase("MAP_NAME", itemName) == 0) { sscanf(line, "%*s %s\n", itemName); if (strcmpignorecase(itemName, mapName) != 0) { skipping = FALSE; fprintf(write, "%s\n", line); } } } line = strtok_r(NULL, "\n", &savePtr); } free(buffer); } /* Save the player's position */ fprintf(write, "MAP_NAME %s\n", mapName); fprintf(write, "PLAYER_DATA\n"); writePlayerToFile(write); fprintf(write, "INVENTORY_INDEX %d\n", getInventoryIndex()); fprintf(write, "PLAYER_INVENTORY\n"); writeInventoryToFile(write); fprintf(write, "ENTITY_DATA\n"); /* Now write out all of the Entities */ writeEntitiesToFile(write); /* Now the targets */ writeTargetsToFile(write); /* And the triggers */ writeTriggersToFile(write); /* Add the global triggers */ writeGlobalTriggersToFile(write); /* Add the map triggers */ writeMapTriggersToFile(write); /* Add the objectives */ writeObjectivesToFile(write); /* Save the player data */ fclose(write); #if DEV == 1 copyFile(tempSaveFile, "savedata"); #endif compressFile(tempSaveFile); copyFile(tempSaveFile, saveFile); remove(tempSaveFile); updateSaveFileIndex(slot); }
static void patchSaveGame(char *saveFile, double version) { char location[MAX_VALUE_LENGTH], *line, *savePtr, itemName[MAX_MESSAGE_LENGTH], *returnedName, mapName[MAX_VALUE_LENGTH]; unsigned char *buffer, *originalBuffer; int savedLocation = FALSE, saveMap; FILE *newSave; savePtr = NULL; freeGameResources(); newSave = fopen(tempFile, "wb"); buffer = decompressFile(saveFile); originalBuffer = malloc((strlen((char *)buffer) + 1) * sizeof(unsigned char)); if (originalBuffer == NULL) { showErrorAndExit("Failed to allocate %d bytes to patch save game", (int)((strlen((char *)buffer) + 1) * sizeof(unsigned char))); } strcpy((char *)originalBuffer, (char *)buffer); line = strtok_r((char *)buffer, "\n", &savePtr); returnedName = NULL; mapName[0] = '\0'; while (line != NULL) { if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } if (line[strlen(line) - 1] == '\r') { line[strlen(line) - 1] = '\0'; } sscanf(line, "%s", itemName); if (strcmpignorecase("PLAYER_LOCATION", itemName) == 0) { sscanf(line, "%*s %s\n", location); } else if (strcmpignorecase("MAP_NAME", itemName) == 0) { saveMap = TRUE; if (strlen(mapName) == 0 || strcmpignorecase(line, mapName) == 0) { sscanf(line, "%*s %s\n", itemName); returnedName = loadResources(savePtr); if (returnedName != NULL) { STRNCPY(mapName, returnedName, sizeof(mapName)); } /* Rewind to start */ free(buffer); buffer = malloc((strlen((char *)originalBuffer) + 1) * sizeof(unsigned char)); if (buffer == NULL) { showErrorAndExit("Failed to allocate %d bytes to patch save game", (int)((strlen((char *)originalBuffer) + 1) * sizeof(unsigned char))); } strcpy((char *)buffer, (char *)originalBuffer); line = strtok_r((char *)buffer, "\n", &savePtr); /* Load up the patch file */ saveMap = patchEntities(version, itemName); if (saveMap == FALSE) { snprintf(itemName, sizeof(itemName), "%ld_old", game.playTime * SDL_GetTicks()); } if (savedLocation == FALSE) { fprintf(newSave, "VERSION %0.2f\n", version); fprintf(newSave, "PLAY_TIME %ld\n", game.playTime); fprintf(newSave, "PLAYER_KILLS %d\n", game.kills); fprintf(newSave, "BATS_DROWNED %d\n", game.batsDrowned); fprintf(newSave, "TIMES_EATEN %d\n", game.timesEaten); fprintf(newSave, "DISTANCE_TRAVELLED %u\n", game.distanceTravelled); fprintf(newSave, "ATTACKS_BLOCKED %d\n", game.attacksBlocked); fprintf(newSave, "SLIME_TIME %d\n", game.timeSpentAsSlime); fprintf(newSave, "ARROWS_FIRED %d\n", game.arrowsFired); fprintf(newSave, "SECRETS_FOUND %d\n", game.secretsFound); fprintf(newSave, "CONTINUES %d\n", game.continues); fprintf(newSave, "CHEATING %d\n", game.cheating); fprintf(newSave, "PLAYER_LOCATION %s\n", location); savedLocation = TRUE; } fprintf(newSave, "MAP_NAME %s\n", itemName); if (strcmpignorecase(itemName, location) == 0) { fprintf(newSave, "PLAYER_DATA\n"); writePlayerToFile(newSave); fprintf(newSave, "PLAYER_INVENTORY\n"); writeInventoryToFile(newSave); } fprintf(newSave, "ENTITY_DATA\n"); /* Now write out all of the Entities */ writeEntitiesToFile(newSave); /* Now the targets */ writeTargetsToFile(newSave); /* And the triggers */ writeTriggersToFile(newSave); /* Add the global triggers */ writeGlobalTriggersToFile(newSave); /* Add the map triggers */ writeMapTriggersToFile(newSave); /* Add the objectives */ writeObjectivesToFile(newSave); freeLevelResources(); if (returnedName == NULL) { break; } } } line = strtok_r(NULL, "\n", &savePtr); } free(buffer); free(originalBuffer); fclose(newSave); #if DEV == 1 copyFile(tempFile, "tmpdata"); #endif copyFile(tempFile, saveFile); compressFile(saveFile); }
static void finalAttack() { Entity *temp; self->thinkTime--; if (self->thinkTime <= 0) { switch (self->mental) { case 0: setEntityAnimation(self, "ATTACK_4"); addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2); playSoundToMap("sound/common/spell", -1, self->x, self->y, 0); self->flags &= ~NO_DRAW; self->face = RIGHT; createAutoDialogBox(_("Sorceror"), _("Enough! Prepare to die..."), 180); self->thinkTime = 180; self->mental = 1; temp = getFreeEntity(); if (temp == NULL) { showErrorAndExit("No free slots to add a the staff"); } loadProperties("boss/sorceror_staff", temp); temp->action = &staffMoveAroundSorceror; temp->draw = &drawLoopingAnimationToMap; temp->type = ENEMY; setEntityAnimationByID(temp, 0); temp->x = self->x + self->w / 2 - temp->w / 2; temp->y = self->y + self->h / 2 - temp->h / 2; temp->startX = temp->x; temp->startY = temp->y; temp->head = self; temp->health = self->health; temp->mental = self->box.w; break; case 1: temp = getFreeEntity(); if (temp == NULL) { showErrorAndExit("No free slots to add a the Final Attack spell"); } loadProperties("boss/sorceror_final_spell", temp); temp->action = &finalSpellWait; temp->draw = &drawLoopingAnimationToMap; temp->type = ENEMY; setEntityAnimationByID(temp, 0); temp->x = self->x + temp->offsetX; temp->y = self->y + temp->offsetY; temp->head = self; temp->thinkTime = 60; self->thinkTime = 660; self->mental = 2; temp->health = self->health; break; default: self->mental = 3; playSoundToMap("sound/common/massive_explosion", -1, self->x, self->y, 0); fadeFromColour(0, 0, 200, 30); /* Gib the player */ temp = self; self = &player; freeEntityList(playerGib()); self = temp; self->thinkTime = 120; self->action = &finalAttackFinish; break; } } else if (self->thinkTime <= 420 && self->mental == 2) { self->startX = 2; } }
static void init() { int i, x, y, col; Entity *e, *prev; prev = self; x = self->x; y = self->y + self->h; col = 1; if (self->mental != 2) { for (i=0;i<50;i++) { /* 4 pegs per row, plus 1 score tile and 10 rows */ e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add a Mastermind Peg"); } if (col == 5) { loadProperties("item/mastermind_score", e); col = 0; e->mental = 1; } else { loadProperties("item/mastermind_peg", e); e->mental = 0; } setEntityAnimation(e, "STAND"); if (i == 0) { y -= TILE_SIZE; } if (i != 0 && i % 5 == 0) { x = self->x; y -= TILE_SIZE; } else if (i != 0) { x += TILE_SIZE; } e->face = RIGHT; e->x = x; e->y = y; e->action = &pegWait; e->draw = &drawLoopingAnimationToMap; prev->target = e; prev = e; e->target = NULL; col++; } generateSolution(); addCursor(); } self->action = &entityWait; }
static void riftAttack() { Entity *e; self->thinkTime--; if (self->thinkTime <= 0) { if (self->mental == 0) { self->y = getMapFloor(self->x + self->w / 2, self->y) - self->h; self->flags &= ~NO_DRAW; addParticleExplosion(self->x + self->w / 2, self->y + self->h / 2); self->mental = 1; self->thinkTime = 60; } else { setEntityAnimation(self, "ATTACK_1"); e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add an Energy Rift"); } loadProperties("enemy/energy_rift", e); e->damage = 1; e->action = &riftMove; e->touch = &entityTouch; e->draw = &drawLoopingAnimationToMap; e->type = ENEMY; setEntityAnimation(e, "STAND"); if (self->face == LEFT) { e->x = self->x - e->w; } else { e->x = self->x + self->w; } e->thinkTime = 15; e->y = self->y; e->dirX = self->face == LEFT ? -e->speed : e->speed; e->head = self; e->targetX = getMapStartX() + SCREEN_WIDTH / 2 - e->w / 2; e->targetY = e->y; e->health = 0; playSoundToMap("sound/common/spell", -1, self->x, self->y, 0); self->mental = -1; self->action = &riftAttackWait; self->thinkTime = 60; } } checkToMap(self); }
static void holdPersonSpellMove() { Entity *e; if (self->target == NULL) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add the Sorceror's Hold Person"); } loadProperties("boss/sorceror_hold_person_spell", e); setEntityAnimation(e, "BACK"); e->face = RIGHT; e->action = &holdPersonBackWait; e->draw = &drawLoopingAnimationToMap; e->x = self->x; e->y = self->y; e->layer = BACKGROUND_LAYER; self->target = e; e->head = self; } switch (self->mental) { case 3: self->targetY = player.y + player.h / 2 - self->h / 2 - 16; break; case 2: self->targetY = player.y + player.h / 2 - self->h / 2; break; default: self->targetY = player.y + player.h / 2 - self->h / 2 + 16; break; } setCustomAction(&player, &stickToFloor, 3, 0, 0); if (self->y < self->targetY) { self->y += 12; if (self->y >= self->targetY) { self->y = self->targetY; self->face = player.face; } } else { if (self->mental == 3) { setInfoBoxMessage(0, 255, 255, 255, _("Quickly turn left and right to remove the hold person spell!")); } if (self->face != player.face) { self->face = player.face; self->health--; if (self->health <= 0) { setEntityAnimation(self, "LEFT_PIECE"); self->layer = FOREGROUND_LAYER; self->dirX = -4; self->action = &holdPersonPieceMove; self->thinkTime = 30; } } } player.x = self->x + self->w / 2 - player.w / 2; }
static void loadMenuLayout(char *text) { int y, i, w, maxWidth; i = 0; menu.widgetCount = 2; menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount); if (menu.widgets == NULL) { showErrorAndExit("Ran out of memory when creating OK Menu"); } menu.widgets[0] = createWidget(text, NULL, NULL, NULL, NULL, -1, 10, FALSE, 255, 255, 255); menu.widgets[1] = createWidget(_("OK"), NULL, NULL, NULL, &doOK, -1, 10, TRUE, 255, 255, 255); y = BUTTON_PADDING + BORDER_PADDING; maxWidth = w = 0; for (i=0;i<menu.widgetCount;i++) { if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth) { maxWidth = menu.widgets[i]->normalState->w; } } for (i=0;i<menu.widgetCount;i++) { menu.widgets[i]->y = y; if (menu.widgets[i]->x != -1) { menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING; } if (menu.widgets[i]->label != NULL) { menu.widgets[i]->label->y = y; menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10; if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w) { w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w; } } else { if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w) { w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w; } } y += menu.widgets[i]->selectedState->h + BUTTON_PADDING; } menu.w = w + BUTTON_PADDING; menu.h = y - BORDER_PADDING; menu.background = addBorder(createSurface(menu.w, menu.h), 255, 255, 255, 0, 0, 0); menu.x = (SCREEN_WIDTH - menu.background->w) / 2; menu.y = (SCREEN_HEIGHT - menu.background->h) / 2; }
static void castLightningBolt() { Entity *e; self->thinkTime--; if (self->thinkTime <= 0) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add lightning"); } loadProperties("enemy/lightning", e); setEntityAnimation(e, "STAND"); e->x = self->x + self->w / 2; e->y = self->y + self->h / 2; e->x -= e->w / 2; e->y -= e->h / 2; e->targetX = player.x + player.w / 2 - e->w / 2; e->targetY = getMapCeiling(self->x, self->y); e->startY = e->targetY; e->endY = getMapFloor(e->targetX, e->targetY); calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY); e->flags |= (NO_DRAW|HELPLESS|TELEPORTING|NO_END_TELEPORT_SOUND); playSoundToMap("sound/common/spell", -1, self->x, self->y, 0); e->head = self; e->face = RIGHT; e->action = &lightningBolt; e->draw = &drawLoopingAnimationToMap; e->head = self; e->face = self->face; e->type = ENEMY; e->thinkTime = 0; e->flags |= FLY|DO_NOT_PERSIST; self->mental--; if (self->mental <= 0) { self->thinkTime = 60; self->action = &attackFinished; } else { self->thinkTime = 30; } } hover(); }
static void dieSplit() { Entity *e; self->thinkTime--; if (self->thinkTime <= 0) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add a Blob Boss Part"); } loadProperties("boss/blob_boss_part", e); e->flags |= LIMIT_TO_SCREEN; setEntityAnimation(e, "STAND"); e->draw = &drawLoopingAnimationToMap; e->type = ENEMY; e->damage = 0; e->touch = NULL; e->head = self; e->action = &partFinalDie; e->die = &entityDieNoDrop; e->x = self->x + self->box.x + self->box.w / 2 - e->w / 2; e->y = self->y + self->box.y + self->box.h / 2 - e->h / 2; e->thinkTime = 120; e->dirX = 10 + prand() % 80; e->dirX /= 10; e->dirX *= prand() % 2 == 0 ? -1 : 1; e->dirY = -4 - prand() % 12; e->targetX = self->x + self->w / 2; self->mental--; if (self->mental == 0) { if (self->currentFrame == 0) { self->flags |= NO_DRAW; self->thinkTime = 120; self->action = &dieWait; return; } else { self->mental = 30; self->currentFrame--; setFrameData(self); } } self->thinkTime = 3; } checkToMap(self); }
static void lightningBolt() { int i, middle; Entity *e; self->flags |= NO_DRAW; self->thinkTime--; middle = -1; if (self->thinkTime <= 0) { playSoundToMap("sound/enemy/thunder_cloud/lightning", -1, self->targetX, self->startY, 0); for (i=self->startY;i<self->endY;i+=32) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add lightning"); } loadProperties("enemy/lightning", e); setEntityAnimation(e, "STAND"); if (i == self->startY) { middle = self->targetX + self->w / 2 - e->w / 2; } e->x = middle; e->y = i; e->action = &lightningWait; e->draw = &drawLoopingAnimationToMap; e->touch = &entityTouch; e->head = self; e->currentFrame = prand() % 6; e->face = RIGHT; e->thinkTime = 15; } e = addSmallRock(self->x, self->endY, "common/small_rock"); e->x += (self->w - e->w) / 2; e->y -= e->h; e->dirX = -3; e->dirY = -8; e = addSmallRock(self->x, self->endY, "common/small_rock"); e->x += (self->w - e->w) / 2; e->y -= e->h; e->dirX = 3; e->dirY = -8; self->inUse = FALSE; } }
static unsigned char *uncompressFileRW(char *name, unsigned long *size) { unsigned char *source, *dest; FILE *fp; #if DEV != 1 int i, index; #endif #if DEV == 1 fp = fopen(name, "rb"); if (fp == NULL) { showErrorAndExit("Failed to open %s", name); } fseek(fp, 0L, SEEK_END); (*size) = ftell(fp); fseek(fp, 0L, SEEK_SET); dest = malloc((*size) * sizeof(unsigned char)); if (dest == NULL) { showErrorAndExit("Failed to allocate %ld bytes to load %s", (*size) * (int)sizeof(unsigned char), name); } fread(dest, (*size), 1, fp); source = NULL; #else index = -1; for (i=0;i<fileCount;i++) { if (strcmpignorecase(fileData[i].filename, name) == 0) { index = i; break; } } if (index == -1) { showErrorAndExit("Failed to find %s in PAK file", name); } fp = fopen(pakFile, "rb"); if (fp == NULL) { showErrorAndExit("Failed to open PAK file %s", pakFile); } fseek(fp, fileData[index].offset, SEEK_SET); source = malloc(fileData[index].compressedSize * sizeof(unsigned char)); if (source == NULL) { showErrorAndExit("Failed to allocate %d bytes to load %s from PAK", fileData[index].compressedSize * (int)sizeof(unsigned char), name); } dest = malloc(fileData[index].fileSize * sizeof(unsigned char)); if (dest == NULL) { showErrorAndExit("Failed to allocate %d bytes to load %s from PAK", fileData[index].fileSize * (int)sizeof(unsigned char), name); } fread(source, fileData[i].compressedSize, 1, fp); (*size) = fileData[index].fileSize; uncompress(dest, size, source, fileData[index].compressedSize); if ((*size) != fileData[index].fileSize) { showErrorAndExit("Failed to decompress %s. Expected %ld, got %ld", fileData[index].filename, fileData[index].fileSize, (*size)); } #endif if (source != NULL) { free(source); } fclose(fp); return dest; }
static void createShield() { int i, x, y; Entity *shield, *e; self->thinkTime--; if (self->thinkTime <= 0) { if (self->mental == 0) { setEntityAnimation(self, "ATTACK_1"); shield = getFreeEntity(); if (shield == NULL) { showErrorAndExit("No free slots to add the Sorceror's Shield"); } loadProperties("boss/sorceror_shield", shield); shield->x = self->x; shield->y = self->y; shield->action = &shieldCreateWait; shield->draw = &drawLoopingAnimationToMap; shield->touch = &entityTouch; shield->takeDamage = &shieldTakeDamage; shield->pain = &enemyPain; shield->die = &shieldDie; shield->type = ENEMY; shield->head = self; shield->alpha = 128; shield->face = RIGHT; shield->maxHealth = self->health; setEntityAnimation(shield, "STAND"); shield->x = self->x + self->w / 2 - shield->w / 2; shield->y = self->y + self->h / 2 - shield->h / 2; shield->flags |= NO_DRAW; self->startX = 1; self->head = shield; shield->mental = 6; x = shield->x; y = shield->y; for (i=0;i<6;i++) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add the Sorceror's Shield Piece"); } loadProperties("boss/sorceror_shield_piece", e); setEntityAnimationByID(e, i); e->x = x; e->y = y; e->startX = e->x; e->startY = e->y; e->action = &pieceMoveToShield; e->draw = &drawLoopingAnimationToMap; e->type = ENEMY; e->alpha = 128; e->face = RIGHT; e->head = shield; if (x == shield->x) { x += e->w; } else { x = shield->x; y += e->h; } switch (i) { case 0: e->dirX = -12; e->dirY = -6; break; case 1: e->dirX = 12; e->dirY = -6; break; case 2: e->dirX = -12; e->dirY = 0; break; case 3: e->dirX = 12; e->dirY = 0; break; case 4: e->dirX = -12; e->dirY = 6; break; default: e->dirX = 12; e->dirY = 6; break; } e->x += e->dirX * 60; e->y += e->dirY * 60; e->dirX *= -1; e->dirY *= -1; } self->mental = 1; } else if (self->mental == 2) { self->thinkTime = 30; self->action = &createShieldFinish; } } }
static void loadMenuLayout() { char *text; int x, y, w, maxWidth, i; menu.widgetCount = 5; menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount); if (menu.widgets == NULL) { showErrorAndExit("Ran out of memory when creating Control Menu"); } x = y = 0; menu.widgets[0] = createWidget(_("Sound"), &control.button[CONTROL_UP], &toggleSound, &toggleSound, &toggleSound, x, y, TRUE, 255, 255, 255); menu.widgets[0]->label = createLabel(game.audio == TRUE || game.audioDisabled == TRUE ? _("Yes") : _("No"), menu.widgets[0]->x + menu.widgets[0]->normalState->w + 10, y); menu.widgets[1] = createWidget(_("SFX Volume"), &game.sfxDefaultVolume, &lowerSFXVolume, &raiseSFXVolume, NULL, x, y, TRUE, 255, 255, 255); text = getVolumePercent(game.sfxDefaultVolume); menu.widgets[1]->label = createLabel(_(text), menu.widgets[1]->x + menu.widgets[1]->normalState->w + 10, y); free(text); menu.widgets[2] = createWidget(_("Music Volume"), &game.musicDefaultVolume, &lowerMusicVolume, &raiseMusicVolume, NULL, x, y, TRUE, 255, 255, 255); text = getVolumePercent(game.musicDefaultVolume); menu.widgets[2]->label = createLabel(_(text), menu.widgets[2]->x + menu.widgets[2]->normalState->w + 10, y); free(text); menu.widgets[3] = createWidget(_("Audio Quality"), &game.audioQuality, &toggleQuality, &toggleQuality, &toggleQuality, x, y, TRUE, 255, 255, 255); text = getQuality(); menu.widgets[3]->label = createLabel(text, menu.widgets[3]->x + menu.widgets[3]->normalState->w + 10, y); free(text); menu.widgets[4] = createWidget(_("Back"), NULL, NULL, NULL, &showOptionsMenu, -1, y, TRUE, 255, 255, 255); y = BUTTON_PADDING + BORDER_PADDING; maxWidth = w = 0; for (i=0;i<menu.widgetCount;i++) { if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth) { maxWidth = menu.widgets[i]->normalState->w; } } for (i=0;i<menu.widgetCount;i++) { menu.widgets[i]->y = y; if (menu.widgets[i]->x != -1) { menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING; } if (menu.widgets[i]->label != NULL) { menu.widgets[i]->label->y = y; menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10; if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w) { w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w; } } else { if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w) { w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w; } } y += menu.widgets[i]->selectedState->h + BUTTON_PADDING; } menu.w = w + BUTTON_PADDING; menu.h = y - BORDER_PADDING; menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0); menu.x = (SCREEN_WIDTH - menu.background->w) / 2; menu.y = (SCREEN_HEIGHT - menu.background->h) / 2; }
static void shieldDie() { int i, x, y; Entity *e; x = self->x; y = self->y; playSoundToMap("sound/boss/sorceror/shield_die", -1, self->x, self->y, 0); for (i=0;i<6;i++) { e = getFreeEntity(); if (e == NULL) { showErrorAndExit("No free slots to add the Sorceror's Shield Piece"); } loadProperties("boss/sorceror_shield_piece", e); e->x = x; e->y = y; e->action = &pieceWait; e->draw = &drawLoopingAnimationToMap; e->type = ENEMY; e->alpha = 128; e->face = RIGHT; setEntityAnimationByID(e, i); if (x == self->x) { x += e->w; } else { x = self->x; y += e->h; } switch (i) { case 0: e->dirX = -3; e->dirY = -1.5f; break; case 1: e->dirX = 3; e->dirY = -1.5f; break; case 2: e->dirX = -3; break; case 3: e->dirX = 3; break; case 4: e->dirX = -3; e->dirY = 1.5f; break; default: e->dirX = 3; e->dirY = 1.5f; break; } } self->head->startY = 0; self->head->startX = 0; self->inUse = FALSE; }
static void createBody() { char bodyName[MAX_VALUE_LENGTH]; int i; Entity **body, *head; body = malloc(self->mental * sizeof(Entity *)); if (body == NULL) { showErrorAndExit("Failed to allocate a whole %d bytes for Snake Boss body...", self->mental * (int)sizeof(Entity *)); } snprintf(bodyName, sizeof(bodyName), "%s_body", self->name); for (i=self->mental-1; i>=0; i--) { body[i] = getFreeEntity(); if (body[i] == NULL) { showErrorAndExit("No free slots to add a Snake Boss body part"); } loadProperties(bodyName, body[i]); body[i]->x = self->x; body[i]->y = self->y; body[i]->action = &bodyWait; body[i]->draw = &drawLoopingAnimationToMap; body[i]->touch = &entityTouch; body[i]->die = &entityDieNoDrop; body[i]->takeDamage = &bodyTakeDamage; body[i]->creditsAction = &bodyWait; body[i]->type = ENEMY; body[i]->active = FALSE; body[i]->flags |= NO_DRAW; setEntityAnimation(body[i], "STAND"); } /* Recreate the head so that it's on top */ head = getFreeEntity(); if (head == NULL) { showErrorAndExit("No free slots to add a Snake Boss head"); } *head = *self; self->inUse = FALSE; self = head; /* Link the sections */ for (i=self->mental-1; i>=0; i--) { if (i == 0) { self->target = body[i]; } else { body[i - 1]->target = body[i]; } body[i]->head = self; } free(body); }
static void callSummoners() { int r; Entity *e; Target *t; self->thinkTime--; if (self->thinkTime <= 0) { setEntityAnimation(self, "ATTACK_1"); self->mental--; playSoundToMap("sound/common/spell", BOSS_CHANNEL, self->x, self->y, 0); e = addEnemy("enemy/sorceror_dark_summoner", 0, 0); e->x = self->x + self->w / 2 - e->w / 2; e->y = self->y + self->h / 2 - e->h / 2; r = prand() % 3; switch (r) { case 0: t = getTargetByName("DARK_SUMMONER_TARGET_0"); break; case 1: t = getTargetByName("DARK_SUMMONER_TARGET_1"); break; default: t = getTargetByName("DARK_SUMMONER_TARGET_2"); break; } if (t == NULL) { showErrorAndExit("Sorceror cannot find target"); } e->targetX = t->x; e->targetY = t->y; e->startX = e->targetX; e->startY = e->targetY; e->maxThinkTime = self->maxThinkTime; calculatePath(e->x, e->y, e->targetX, e->targetY, &e->dirX, &e->dirY); e->flags |= (NO_DRAW|HELPLESS|TELEPORTING); e->head = self; if (self->mental <= 0) { setEntityAnimation(self, "STAND"); self->maxThinkTime++; self->action = &callSummonersWait; } self->thinkTime = 30; } hover(); }
static void removeItems() { int i, j, size, count, x, allTargets; Entity *e; Target *t; char targetName[MAX_LINE_LENGTH]; char *items[] = { "item/tuning_fork", "item/coal", "item/invisibility_potion", "item/repellent", "item/water_purifier", "item/extend_o_grab", "item/bomb", "item/sludge_tentacle", "item/gazer_eye", "weapon/normal_arrow" }; size = sizeof(items) / sizeof(char *); resetInventoryIndex(); count = 0; allTargets = 0; /* Remove all the inventory items */ for (i=0;i<MAX_INVENTORY_ITEMS;i++) { e = removeInventoryItemAtCursor(); if (e != NULL) { for (j=0;j<size;j++) { if (strcmpignorecase(e->name, items[j]) == 0) { e->inUse = FALSE; break; } } if (e->inUse == FALSE) { continue; } if (strcmpignorecase(e->name, "item/health_potion") == 0) { e->mental = -1; } /* Ensure that at least 1 item appears at each target */ j = allTargets < self->mental ? allTargets : prand() % self->mental; allTargets++; snprintf(targetName, MAX_VALUE_LENGTH, "REMOVER_TARGET_%d", j); t = getTargetByName(targetName); if (t == NULL) { showErrorAndExit("Item Remover cannot find target"); } x = t->x; x += (prand() % 32) * (prand() % 2 == 0 ? -1 : 1); addEntity(*e, x, t->y); e->inUse = FALSE; snprintf(targetName, MAX_LINE_LENGTH, "\"%s\" 1 UPDATE_TRIGGER \"ITEMS\"", e->objectiveName); count++; addGlobalTriggerFromScript(targetName); } } freeInventory(); snprintf(targetName, MAX_LINE_LENGTH, "\"ITEMS\" %d UPDATE_OBJECTIVE \"Retrieve items\"", count); addGlobalTriggerFromScript(targetName); e = removePlayerWeapon(); if (e != NULL) { e->inUse = FALSE; } e = removePlayerShield(); if (e != NULL) { e->inUse = FALSE; } self->inUse = FALSE; }
int loadContinueData() { char itemName[MAX_MESSAGE_LENGTH], mapName[MAX_MESSAGE_LENGTH]; char saveFile[MAX_PATH_LENGTH], *line, *savePtr; unsigned char *buffer; FILE *fp; savePtr = NULL; snprintf(saveFile, sizeof(saveFile), "%scontinuesave", gameSavePath); fp = fopen(saveFile, "rb"); if (fp == NULL) { return FALSE; } fclose(fp); freeGameResources(); initGame(); game.canContinue = TRUE; buffer = decompressFile(saveFile); if (strlen((char *)buffer) == 0) { showErrorAndExit("Something went wrong when decompressing the continue file"); } line = strtok_r((char *)buffer, "\n", &savePtr); while (line != NULL) { if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } if (line[strlen(line) - 1] == '\r') { line[strlen(line) - 1] = '\0'; } sscanf(line, "%s", itemName); if (strcmpignorecase("PLAY_TIME", itemName) == 0) { sscanf(line, "%*s %ld\n", &game.playTime); } else if (strcmpignorecase("PLAYER_KILLS", itemName) == 0) { sscanf(line, "%*s %d\n", &game.kills); } else if (strcmpignorecase("BATS_DROWNED", itemName) == 0) { sscanf(line, "%*s %d\n", &game.batsDrowned); } else if (strcmpignorecase("TIMES_EATEN", itemName) == 0) { sscanf(line, "%*s %d\n", &game.timesEaten); } else if (strcmpignorecase("DISTANCE_TRAVELLED", itemName) == 0) { sscanf(line, "%*s %u\n", &game.distanceTravelled); } else if (strcmpignorecase("ATTACKS_BLOCKED", itemName) == 0) { sscanf(line, "%*s %d\n", &game.attacksBlocked); } else if (strcmpignorecase("SLIME_TIME", itemName) == 0) { sscanf(line, "%*s %d\n", &game.timeSpentAsSlime); } else if (strcmpignorecase("ARROWS_FIRED", itemName) == 0) { sscanf(line, "%*s %d\n", &game.arrowsFired); } else if (strcmpignorecase("SECRETS_FOUND", itemName) == 0) { sscanf(line, "%*s %d\n", &game.secretsFound); } else if (strcmpignorecase("CONTINUES", itemName) == 0) { sscanf(line, "%*s %d\n", &game.continues); } else if (strcmpignorecase("CHEATING", itemName) == 0) { sscanf(line, "%*s %d\n", &game.cheating); } else if (strcmpignorecase("PLAYER_LOCATION", itemName) == 0) { sscanf(line, "%*s %s\n", itemName); loadMap(itemName, FALSE); snprintf(mapName, sizeof(mapName), "MAP_NAME %s", itemName); } else if (strcmpignorecase(line, mapName) == 0) { loadResources(savePtr); } line = strtok_r(NULL, "\n", &savePtr); } free(buffer); copyFile(saveFile, tempFile); buffer = decompressFile(tempFile); free(buffer); cameraSnapToTargetEntity(); freeMessageQueue(); return TRUE; }