Merge branch 'master' into rebalance

This commit is contained in:
Andrei "Akari" Alexeyev 2017-04-06 03:59:46 +03:00
commit a175c38416
7 changed files with 195 additions and 30 deletions

View file

@ -25,11 +25,19 @@ Boss* create_boss(char *name, char *ani, char *dialog, complex pos) {
return buf;
}
void draw_boss_text_ex(Alignment align, float x, float y, const char *text, TTF_Font *fnt, float alpha) {
glColor4f(0,0,0,alpha);
draw_text(align, x+1, y+1, text, fnt);
glColor4f(1,1,1,alpha);
draw_text(align, x, y, text, fnt);
if(alpha < 1) {
glColor4f(1,1,1,1);
}
}
void draw_boss_text(Alignment align, float x, float y, const char *text) {
glColor4f(0,0,0,1);
draw_text(align, x+1, y+1, text, _fonts.standard);
glColor4f(1,1,1,1);
draw_text(align, x, y, text, _fonts.standard);
draw_boss_text_ex(align, x, y, text, _fonts.standard, 1);
}
void spell_opening(Boss *b, int time) {
@ -78,6 +86,34 @@ Color boss_healthbar_color(AttackType atype) {
}
}
static StageProgress* get_spellstage_progress(Attack *a, StageInfo **out_stginfo, bool write) {
if(out_stginfo) {
*out_stginfo = NULL;
}
if(!write || (global.replaymode == REPLAY_RECORD && global.stage->type == STAGE_STORY)) {
StageInfo *i = stage_get_by_spellcard(a->info, global.diff);
if(i) {
StageProgress *p = stage_get_progress_from_info(i, global.diff, write);
if(out_stginfo) {
*out_stginfo = i;
}
if(p) {
return p;
}
}
#if DEBUG
else if(a->type == AT_Spellcard || a->type == AT_ExtraSpell) {
log_warn("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
}
#endif
}
return NULL;
}
void draw_boss(Boss *boss) {
draw_animation_p(creal(boss->pos), cimag(boss->pos) + 6*sin(global.frames/25.0), boss->anirow, boss->ani);
draw_boss_text(AL_Left, 10, 20, boss->name);
@ -90,9 +126,21 @@ void draw_boss(Boss *boss) {
if(boss->current->type != AT_Move) {
char buf[16];
snprintf(buf, sizeof(buf), "%.2f", max(0, (boss->current->timeout - global.frames + boss->current->starttime)/(float)FPS));
draw_boss_text(AL_Center, VIEWPORT_W - 20, 10, buf);
StageProgress *p = get_spellstage_progress(boss->current, NULL, false);
if(p) {
float a = clamp((global.frames - boss->current->starttime - 60) / 60.0, 0, 1);
snprintf(buf, sizeof(buf), "%u / %u", p->num_cleared, p->num_played);
draw_boss_text_ex(AL_Right,
VIEWPORT_W + stringwidth(buf, _fonts.small) * pow(1 - a, 2),
35 + stringheight(buf, _fonts.small),
buf, _fonts.small, a
);
}
int nextspell, lastspell;
for(nextspell = 0; nextspell < boss->acount - 1; nextspell++) {
int t = boss->attacks[nextspell].type;
@ -256,6 +304,14 @@ void boss_finish_current_attack(Boss *boss) {
AttackType t = boss->current->type;
if(t == AT_Spellcard || t == AT_ExtraSpell || t == AT_SurvivalSpell) {
boss_give_spell_bonus(boss, boss->current, &global.plr);
if(!boss->current->failtime) {
StageProgress *p = get_spellstage_progress(boss->current, NULL, true);
if(p) {
++p->num_cleared;
}
}
}
}
@ -383,20 +439,16 @@ void free_attack(Attack *a) {
void start_attack(Boss *b, Attack *a) {
log_debug("%s", a->name);
if(global.replaymode == REPLAY_RECORD && global.stage->type == STAGE_STORY && !global.continues) {
StageInfo *i = stage_get_by_spellcard(a->info, global.diff);
if(i) {
StageProgress *p = stage_get_progress_from_info(i, global.diff, true);
if(p && !p->unlocked) {
log_info("Spellcard unlocked! %s: %s", i->title, i->subtitle);
p->unlocked = true;
}
StageInfo *i;
StageProgress *p = get_spellstage_progress(a, &i, true);
if(p) {
++p->num_played;
if(!p->unlocked && !global.continues) {
log_info("Spellcard unlocked! %s: %s", i->title, i->subtitle);
p->unlocked = true;
}
#if DEBUG
else if(a->type == AT_Spellcard || a->type == AT_ExtraSpell) {
log_warn("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
}
#endif
}
a->starttime = global.frames + (a->type == AT_ExtraSpell? ATTACK_START_DELAY_EXTRA : ATTACK_START_DELAY);

View file

@ -11,8 +11,6 @@
#include "color.h"
struct Color;
typedef enum {
D_Any = 0,
D_Easy,

View file

@ -39,6 +39,9 @@
- PCMD_HISCORE
Sets the "Hi-Score" (highest score ever attained in one game session)
- PCMD_STAGE_PLAYINFO
Sets the times played and times cleared counters for a list of stage/difficulty combinations
*/
/*
@ -174,6 +177,19 @@ 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;
}
}
@ -309,6 +325,80 @@ static void progress_write_cmd_hiscore(SDL_RWops *vfile, void **arg) {
SDL_WriteLE32(vfile, progress.hiscore);
}
//
// PCMD_STAGE_PLAYINFO
//
struct cmd_stage_playinfo_data_elem {
struct cmd_stage_playinfo_data_elem *next;
struct cmd_stage_playinfo_data_elem *prev;
uint16_t stage;
uint8_t diff;
uint32_t num_played;
uint32_t num_cleared;
};
struct cmd_stage_playinfo_data {
size_t size;
struct cmd_stage_playinfo_data_elem *elems;
};
static void progress_prepare_cmd_stage_playinfo(size_t *bufsize, void **arg) {
struct cmd_stage_playinfo_data *data = malloc(sizeof(struct cmd_stage_playinfo_data));
memset(data, 0, sizeof(struct cmd_stage_playinfo_data));
for(StageInfo *stg = stages; stg->procs; ++stg) {
Difficulty d_first, d_last;
if(stg->difficulty == D_Any) {
d_first = D_Easy;
d_last = D_Lunatic;
} else {
d_first = d_last = D_Any;
}
for(Difficulty d = d_first; d <= d_last; ++d) {
StageProgress *p = stage_get_progress_from_info(stg, d, false);
if(p && (p->num_played || p->num_cleared)) {
struct cmd_stage_playinfo_data_elem *e = create_element((void**)&data->elems, sizeof(struct cmd_stage_playinfo_data_elem));
e->stage = stg->id; data->size += sizeof(uint16_t);
e->diff = d; data->size += sizeof(uint8_t);
e->num_played = p->num_played; data->size += sizeof(uint32_t);
e->num_cleared = p->num_cleared; data->size += sizeof(uint32_t);
}
}
}
*arg = data;
if(data->size) {
*bufsize += CMD_HEADER_SIZE + data->size;
}
}
static void progress_write_cmd_stage_playinfo(SDL_RWops *vfile, void **arg) {
struct cmd_stage_playinfo_data *data = *arg;
if(!data->size) {
goto cleanup;
}
SDL_WriteU8(vfile, PCMD_STAGE_PLAYINFO);
SDL_WriteLE16(vfile, data->size);
for(struct cmd_stage_playinfo_data_elem *e = data->elems; e; e = e->next) {
SDL_WriteLE16(vfile, e->stage);
SDL_WriteU8(vfile, e->diff);
SDL_WriteLE32(vfile, e->num_played);
SDL_WriteLE32(vfile, e->num_cleared);
}
cleanup:
delete_all_elements((void**)&data->elems, delete_element);
free(data);
}
//
// Copy unhandled commands from the original file
//
@ -349,6 +439,7 @@ static void progress_write(SDL_RWops *file) {
{progress_prepare_cmd_unlock_stages, progress_write_cmd_unlock_stages, NULL},
{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_test, progress_write_cmd_test, NULL},
{progress_prepare_cmd_unknown, progress_write_cmd_unknown, NULL},
{NULL}

View file

@ -15,22 +15,26 @@
#define PROGRESS_MAXFILESIZE 4096
#ifdef DEBUG
// #define PROGRESS_UNLOCK_ALL
// #define PROGRESS_UNLOCK_ALL
#endif
typedef enum ProgfileCommand {
PCMD_UNLOCK_STAGES,
PCMD_UNLOCK_STAGES_WITH_DIFFICULTY,
PCMD_HISCORE,
// do not reorder this!
PCMD_UNLOCK_STAGES = 0x00,
PCMD_UNLOCK_STAGES_WITH_DIFFICULTY = 0x01,
PCMD_HISCORE = 0x02,
PCMD_STAGE_PLAYINFO = 0x03,
} ProgfileCommand;
typedef struct StageProgress {
// keep this struct small if you can, it leaks
// see stage_get_progress_from_info() in stage.c for more information
// keep this struct small if you can
// see stage_get_progress_from_info() in stage.c for more information
bool unlocked;
// short num_played;
// short num_cleared;
unsigned int unlocked : 1;
uint32_t num_played;
uint32_t num_cleared;
} StageProgress;
struct UnknownCmd;

View file

@ -101,14 +101,14 @@ void init_fonts(void) {
fontrenderer_init(&resources.fontren);
_fonts.standard = load_font("gfx/LinBiolinum.ttf", 20);
_fonts.mainmenu = load_font("gfx/immortal.ttf", 35);
_fonts.small = load_font("gfx/LinBiolinum.ttf", 14);
}
void free_fonts(void) {
fontrenderer_free(&resources.fontren);
TTF_CloseFont(_fonts.standard);
TTF_CloseFont(_fonts.mainmenu);
TTF_CloseFont(_fonts.small);
TTF_Quit();
}

View file

@ -49,6 +49,7 @@ int charwidth(char c, TTF_Font *font);
struct Fonts {
TTF_Font *standard;
TTF_Font *mainmenu;
TTF_Font *small;
};
extern struct Fonts _fonts;

View file

@ -876,6 +876,16 @@ void stage_finish(int gameover) {
assert(global.game_over != GAMEOVER_TRANSITIONING);
global.game_over = GAMEOVER_TRANSITIONING;
set_transition_callback(TransFadeBlack, FADE_TIME, FADE_TIME*2, stage_finalize, (void*)(intptr_t)gameover);
if(global.replaymode == REPLAY_PLAY) {
return;
}
StageProgress *p = stage_get_progress_from_info(global.stage, global.diff, true);
if(p) {
++p->num_cleared;
}
}
static void stage_preload(void) {
@ -941,6 +951,15 @@ void stage_loop(StageInfo *stage) {
}
log_debug("Random seed: %u", seed);
StageProgress *p = stage_get_progress_from_info(stage, global.diff, true);
if(p) {
log_debug("You played this stage %u times", p->num_played);
log_debug("You cleared this stage %u times", p->num_cleared);
++p->num_played;
}
} else {
if(!global.replay_stage) {
log_fatal("Attemped to replay a NULL stage");