track achieved endings

can be used later for unlockables
This commit is contained in:
Andrei "Akari" Alexeyev 2017-04-07 20:34:35 +03:00
parent 757ec9e15e
commit 3a7fef4d9c
4 changed files with 105 additions and 13 deletions

View file

@ -9,6 +9,12 @@
#include "ending.h"
#include "global.h"
#include "video.h"
#include "progress.h"
static void track_ending(int ending) {
assert(ending >= 0 && ending < NUM_ENDINGS);
progress.achieved_endings[ending]++;
}
void add_ending_entry(Ending *e, int dur, char *msg, char *tex) {
EndingEntry *entry;
@ -32,6 +38,7 @@ void bad_ending_marisa(Ending *e) {
add_ending_entry(e, 300, "Maybe all of this was just a daydream.", NULL);
add_ending_entry(e, 300, "Nevertheless, she had won the fight. Thats all that counts… isnt it?", NULL);
add_ending_entry(e, 200, "[Bad Ending 1]", NULL);
track_ending(ENDING_BAD_1);
}
void bad_ending_youmu(Ending *e) {
@ -40,6 +47,7 @@ void bad_ending_youmu(Ending *e) {
add_ending_entry(e, 400, "Yōmu was relieved, but she felt that the real mystery of the land\nbehind the tunnel was left unsolved forever.", NULL);
add_ending_entry(e, 300, "This feeling of discontent would haunt her for a long time to come…", NULL);
add_ending_entry(e, 200, "[Bad Ending 2]", NULL);
track_ending(ENDING_BAD_2);
}
void good_ending_marisa(Ending *e) {
@ -48,6 +56,7 @@ void good_ending_marisa(Ending *e) {
add_ending_entry(e, 350, "Who was the real culprit? What were their motives?", NULL);
add_ending_entry(e, 350, "She craved to find out…", NULL);
add_ending_entry(e, 200, "[Good Ending 1]", NULL);
track_ending(ENDING_GOOD_1);
}
void good_ending_youmu(Ending *e) {
@ -56,6 +65,7 @@ void good_ending_youmu(Ending *e) {
add_ending_entry(e, 320, "Elly promised to fix up the the border as soon as possible.", NULL);
add_ending_entry(e, 350, "But before the path to this unknown place was sealed forever,\nYōmu decided to travel it once more…", NULL);
add_ending_entry(e, 200, "[Good Ending 2]", NULL);
track_ending(ENDING_GOOD_2);
}
void create_ending(Ending *e) {

View file

@ -16,6 +16,16 @@ enum {
ENDING_FADE_TIME = 60,
};
enum {
// do not reorder these or change the values
ENDING_BAD_1,
ENDING_BAD_2,
ENDING_GOOD_1,
ENDING_GOOD_2,
NUM_ENDINGS,
};
typedef struct EndingEntry EndingEntry;
struct EndingEntry {
char *msg;

View file

@ -42,6 +42,9 @@
- PCMD_STAGE_PLAYINFO
Sets the times played and times cleared counters for a list of stage/difficulty combinations
- PCMD_ENDINGS
Sets the the number of times an ending was achieved for a list of endings
*/
/*
@ -167,6 +170,41 @@ static void progress_read(SDL_RWops *file) {
progress.hiscore = SDL_ReadLE32(vfile);
break;
case PCMD_STAGE_PLAYINFO:
while(cur < cmdsize) {
uint16_t stg = SDL_ReadLE16(vfile); cur += sizeof(uint16_t);
Difficulty diff = SDL_ReadU8(vfile); cur += sizeof(uint8_t);
StageProgress *p = stage_get_progress(stg, diff, true);
assert(p != NULL);
uint32_t np = SDL_ReadLE32(vfile); cur += sizeof(uint32_t);
uint32_t nc = SDL_ReadLE32(vfile); cur += sizeof(uint32_t);
if(p) {
p->num_played = np;
p->num_cleared = nc;
} else {
// won't get here in debug builds due to the assertion above,
// but this case should still be handled gracefully in release builds.
log_warn("Invalid stage %x ignored", stg);
}
}
break;
case PCMD_ENDINGS:
while(cur < cmdsize) {
uint8_t ending = SDL_ReadU8(vfile); cur += sizeof(uint8_t);
uint32_t num_achieved = SDL_ReadLE32(vfile); cur += sizeof(uint32_t);
if(ending < NUM_ENDINGS) {
progress.achieved_endings[ending] = num_achieved;
} else {
log_warn("Invalid ending %u ignored", ending);
}
}
break;
default:
log_warn("Unknown command %i (%u bytes). Will preserve as-is and not interpret.", cmd, cmdsize);
@ -177,19 +215,6 @@ static void progress_read(SDL_RWops *file) {
SDL_RWread(vfile, c->data, c->size, 1);
break;
case PCMD_STAGE_PLAYINFO:
while(cur < cmdsize) {
uint16_t stg = SDL_ReadLE16(vfile); cur += sizeof(uint16_t);
Difficulty diff = SDL_ReadU8(vfile); cur += sizeof(uint8_t);
StageProgress *p = stage_get_progress(stg, diff, true);
assert(p != NULL);
p->num_played = SDL_ReadLE32(vfile); cur += sizeof(uint32_t);
p->num_cleared = SDL_ReadLE32(vfile); cur += sizeof(uint32_t);
}
break;
}
}
@ -399,6 +424,45 @@ cleanup:
free(data);
}
//
// PCMD_ENDINGS
//
static void progress_prepare_cmd_endings(size_t *bufsize, void **arg) {
int n = 0;
*arg = 0;
for(int i = 0; i < NUM_ENDINGS; ++i) {
if(progress.achieved_endings[i]) {
++n;
}
}
if(n) {
uint16_t sz = n * (sizeof(uint8_t) + sizeof(uint32_t));
*arg = (void*)(uintptr_t)sz;
*bufsize += CMD_HEADER_SIZE + sz;
}
}
static void progress_write_cmd_endings(SDL_RWops *vfile, void **arg) {
uint16_t sz = (uintptr_t)*arg;
if(!sz) {
return;
}
SDL_WriteU8(vfile, PCMD_ENDINGS);
SDL_WriteLE16(vfile, sz);
for(int i = 0; i < NUM_ENDINGS; ++i) {
if(progress.achieved_endings[i]) {
SDL_WriteU8(vfile, i);
SDL_WriteLE32(vfile, progress.achieved_endings[i]);
}
}
}
//
// Copy unhandled commands from the original file
//
@ -440,13 +504,16 @@ static void progress_write(SDL_RWops *file) {
{progress_prepare_cmd_unlock_stages_with_difficulties, progress_write_cmd_unlock_stages_with_difficulties, NULL},
{progress_prepare_cmd_hiscore, progress_write_cmd_hiscore, NULL},
{progress_prepare_cmd_stage_playinfo, progress_write_cmd_stage_playinfo, NULL},
{progress_prepare_cmd_endings, progress_write_cmd_endings, NULL},
// {progress_prepare_cmd_test, progress_write_cmd_test, NULL},
{progress_prepare_cmd_unknown, progress_write_cmd_unknown, NULL},
{NULL}
};
for(cmd_writer_t *w = cmdtable; w->prepare; ++w) {
size_t oldsize = bufsize;
w->prepare(&bufsize, &w->data);
log_debug("prepare %i: %i", (int)(w - cmdtable), (int)(bufsize - oldsize));
}
if(!bufsize) {
@ -458,7 +525,9 @@ static void progress_write(SDL_RWops *file) {
SDL_RWops *vfile = SDL_RWFromMem(buf, bufsize);
for(cmd_writer_t *w = cmdtable; w->prepare; ++w) {
size_t oldpos = SDL_RWtell(vfile);
w->write(vfile, &w->data);
log_debug("write %i: %i", (int)(w - cmdtable), (int)(SDL_RWtell(vfile) - oldpos));
}
if(SDL_RWtell(vfile) != bufsize) {

View file

@ -10,6 +10,7 @@
#include <stdbool.h>
#include <SDL.h>
#include "ending.h"
#define PROGRESS_FILENAME "progress.dat"
#define PROGRESS_MAXFILESIZE 4096
@ -25,6 +26,7 @@ typedef enum ProgfileCommand {
PCMD_UNLOCK_STAGES_WITH_DIFFICULTY = 0x01,
PCMD_HISCORE = 0x02,
PCMD_STAGE_PLAYINFO = 0x03,
PCMD_ENDINGS = 0x04,
} ProgfileCommand;
typedef struct StageProgress {
@ -41,6 +43,7 @@ struct UnknownCmd;
typedef struct GlobalProgress {
uint32_t hiscore;
uint32_t achieved_endings[NUM_ENDINGS];
struct UnknownCmd *unknown;
} GlobalProgress;