track achieved endings
can be used later for unlockables
This commit is contained in:
parent
757ec9e15e
commit
3a7fef4d9c
4 changed files with 105 additions and 13 deletions
10
src/ending.c
10
src/ending.c
|
@ -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. That’s all that counts… isn’t 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) {
|
||||
|
|
10
src/ending.h
10
src/ending.h
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue