Player Statistics (#219)
This commit is contained in:
parent
7d7f1b157f
commit
56e64498a6
14 changed files with 154 additions and 23 deletions
|
@ -328,7 +328,7 @@ void good_ending_reimu(Ending *e) {
|
|||
static void init_ending(Ending *e) {
|
||||
dynarray_ensure_capacity(&e->entries, 32);
|
||||
|
||||
if(global.plr.continues_used) {
|
||||
if(global.plr.stats.total.continues_used) {
|
||||
global.plr.mode->character->ending.bad(e);
|
||||
} else {
|
||||
global.plr.mode->character->ending.good(e);
|
||||
|
|
|
@ -343,6 +343,7 @@ static void main_singlestg_begin_game(CallChainResult ccr) {
|
|||
replay_init(&global.replay);
|
||||
global.gameover = 0;
|
||||
player_init(&global.plr);
|
||||
stats_init(&global.plr.stats);
|
||||
|
||||
if(ctx->plrmode) {
|
||||
global.plr.mode = ctx->plrmode;
|
||||
|
|
|
@ -91,6 +91,7 @@ static void reset_game(StartGameContext *ctx) {
|
|||
replay_destroy(&global.replay);
|
||||
replay_init(&global.replay);
|
||||
player_init(&global.plr);
|
||||
stats_init(&global.plr.stats);
|
||||
global.plr.mode = plrmode_find(
|
||||
progress.game_settings.character,
|
||||
progress.game_settings.shotmode
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "menu.h"
|
||||
#include "gameovermenu.h"
|
||||
#include "ingamemenu.h"
|
||||
#include "stats.h"
|
||||
#include "global.h"
|
||||
|
||||
static void continue_game(MenuData *m, void *arg) {
|
||||
|
@ -20,7 +21,7 @@ static void continue_game(MenuData *m, void *arg) {
|
|||
}
|
||||
|
||||
static void give_up(MenuData *m, void *arg) {
|
||||
global.gameover = (MAX_CONTINUES - global.plr.continues_used)? GAMEOVER_ABORT : GAMEOVER_DEFEAT;
|
||||
global.gameover = (MAX_CONTINUES - global.plr.stats.total.continues_used) ? GAMEOVER_ABORT : GAMEOVER_DEFEAT;
|
||||
}
|
||||
|
||||
MenuData* create_gameover_menu(void) {
|
||||
|
@ -40,9 +41,9 @@ MenuData* create_gameover_menu(void) {
|
|||
m->context = "Game Over";
|
||||
|
||||
char s[64];
|
||||
int c = MAX_CONTINUES - global.plr.continues_used;
|
||||
int c = MAX_CONTINUES - global.plr.stats.total.continues_used;
|
||||
snprintf(s, sizeof(s), "Continue (%i)", c);
|
||||
add_menu_entry(m, s, c? continue_game : NULL, NULL);
|
||||
add_menu_entry(m, s, c ? continue_game : NULL, NULL);
|
||||
add_menu_entry(m, "Restart the Game", restart_game, NULL)->transition = TransFadeBlack;
|
||||
add_menu_entry(m, c? "Give up" : "Return to Title", give_up, NULL)->transition = TransFadeBlack;
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ taisei_src = files(
|
|||
'stageobjects.c',
|
||||
'stagetext.c',
|
||||
'stageutils.c',
|
||||
'stats.c',
|
||||
'taskmanager.c',
|
||||
'transition.c',
|
||||
'version.c',
|
||||
|
|
20
src/player.c
20
src/player.c
|
@ -16,6 +16,7 @@
|
|||
#include "stage.h"
|
||||
#include "stagetext.h"
|
||||
#include "stagedraw.h"
|
||||
#include "stats.h"
|
||||
#include "entity.h"
|
||||
#include "util/glm.h"
|
||||
|
||||
|
@ -590,7 +591,7 @@ DEFINE_TASK(player_logic) {
|
|||
plr->point_item_value = PLR_START_PIV;
|
||||
plr->life_fragments = 0;
|
||||
plr->bomb_fragments = 0;
|
||||
plr->continues_used += 1;
|
||||
stats_track_continue_used(&plr->stats);
|
||||
player_set_power(plr, 0);
|
||||
stage_clear_hazards(CLEAR_HAZARDS_ALL);
|
||||
spawn_items(plr->deathpos, ITEM_POWER, (int)ceil(PLR_MAX_POWER/(double)POWER_VALUE));
|
||||
|
@ -638,6 +639,19 @@ DEFINE_TASK(player_logic) {
|
|||
void player_logic(Player* plr) {
|
||||
}
|
||||
|
||||
static bool player_can_bomb(Player *plr) {
|
||||
return (
|
||||
!player_is_bomb_active(plr)
|
||||
&& (
|
||||
plr->bombs > 0 ||
|
||||
plr->iddqd
|
||||
)
|
||||
&& global.frames >= plr->respawntime
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static bool player_bomb(Player *plr) {
|
||||
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell)
|
||||
return false;
|
||||
|
@ -648,7 +662,8 @@ static bool player_bomb(Player *plr) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!player_is_bomb_active(plr) && (plr->bombs > 0 || plr->iddqd) && global.frames >= plr->respawntime) {
|
||||
if(player_can_bomb(plr)) {
|
||||
stats_track_bomb_used(&plr->stats);
|
||||
player_fail_spell(plr);
|
||||
// player_cancel_powersurge(plr);
|
||||
// stage_clear_hazards(CLEAR_HAZARDS_ALL);
|
||||
|
@ -885,6 +900,7 @@ void player_realdeath(Player *plr) {
|
|||
plr->bomb_fragments = 0;
|
||||
plr->voltage *= 0.9;
|
||||
plr->lives--;
|
||||
stats_track_life_used(&plr->stats);
|
||||
}
|
||||
|
||||
static void player_death_effect_draw_overlay(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "enemy.h"
|
||||
#include "gamepad.h"
|
||||
#include "aniplayer.h"
|
||||
#include "stats.h"
|
||||
#include "resource/animation.h"
|
||||
#include "entity.h"
|
||||
|
||||
|
@ -102,6 +103,8 @@ DEFINE_ENTITY_TYPE(Player, {
|
|||
AniPlayer ani;
|
||||
Sprite bomb_portrait;
|
||||
|
||||
Stats stats;
|
||||
|
||||
struct {
|
||||
float positive;
|
||||
float negative;
|
||||
|
@ -133,7 +136,6 @@ DEFINE_ENTITY_TYPE(Player, {
|
|||
int bombs;
|
||||
int life_fragments;
|
||||
int bomb_fragments;
|
||||
int continues_used;
|
||||
int power;
|
||||
int power_overflow;
|
||||
|
||||
|
|
35
src/replay.c
35
src/replay.c
|
@ -41,7 +41,7 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t start_t
|
|||
s->plr_pos_y = floor(cimag(plr->pos));
|
||||
|
||||
s->plr_points = plr->points;
|
||||
s->plr_continues_used = plr->continues_used;
|
||||
s->plr_continues_used = plr->stats.total.continues_used;
|
||||
// s->plr_focus = plr->focus; FIXME remove and bump version
|
||||
s->plr_char = plr->mode->character->id;
|
||||
s->plr_shot = plr->mode->shot_mode;
|
||||
|
@ -60,7 +60,7 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t start_t
|
|||
|
||||
void replay_stage_sync_player_state(ReplayStage *stg, Player *plr) {
|
||||
plr->points = stg->plr_points;
|
||||
plr->continues_used = stg->plr_continues_used;
|
||||
plr->stats.total.continues_used = stg->plr_continues_used;
|
||||
plr->mode = plrmode_find(stg->plr_char, stg->plr_shot);
|
||||
plr->pos = stg->plr_pos_x + I * stg->plr_pos_y;
|
||||
// plr->focus = stg->plr_focus; FIXME remove and bump version
|
||||
|
@ -73,6 +73,12 @@ void replay_stage_sync_player_state(ReplayStage *stg, Player *plr) {
|
|||
plr->graze = stg->plr_graze;
|
||||
plr->point_item_value = stg->plr_point_item_value;
|
||||
plr->inputflags = stg->plr_inputflags;
|
||||
|
||||
plr->stats.total.lives_used = stg->plr_stats_total_lives_used;
|
||||
plr->stats.stage.lives_used = stg->plr_stats_stage_lives_used;
|
||||
plr->stats.total.bombs_used = stg->plr_stats_total_bombs_used;
|
||||
plr->stats.stage.bombs_used = stg->plr_stats_stage_bombs_used;
|
||||
plr->stats.stage.continues_used = stg->plr_stats_stage_continues_used;
|
||||
}
|
||||
|
||||
static void replay_destroy_stage(ReplayStage *stage) {
|
||||
|
@ -194,6 +200,14 @@ static uint32_t replay_calc_stageinfo_checksum(ReplayStage *stg, uint16_t versio
|
|||
cs += stg->plr_points_final;
|
||||
}
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS104000_REV0) {
|
||||
cs += stg->plr_stats_total_lives_used;
|
||||
cs += stg->plr_stats_stage_lives_used;
|
||||
cs += stg->plr_stats_total_bombs_used;
|
||||
cs += stg->plr_stats_stage_bombs_used;
|
||||
cs += stg->plr_stats_stage_continues_used;
|
||||
}
|
||||
|
||||
log_debug("%08x", cs);
|
||||
return cs;
|
||||
}
|
||||
|
@ -226,6 +240,14 @@ static bool replay_write_stage(ReplayStage *stg, SDL_RWops *file, uint16_t versi
|
|||
SDL_WriteLE64(file, stg->plr_points_final);
|
||||
}
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS104000_REV0) {
|
||||
SDL_WriteU8(file, stg->plr_stats_total_lives_used);
|
||||
SDL_WriteU8(file, stg->plr_stats_stage_lives_used);
|
||||
SDL_WriteU8(file, stg->plr_stats_total_bombs_used);
|
||||
SDL_WriteU8(file, stg->plr_stats_stage_bombs_used);
|
||||
SDL_WriteU8(file, stg->plr_stats_stage_continues_used);
|
||||
}
|
||||
|
||||
if(stg->events.num_elements > UINT16_MAX) {
|
||||
log_error("Too many events in replay, cannot write this");
|
||||
return false;
|
||||
|
@ -371,6 +393,7 @@ static bool replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, s
|
|||
case REPLAY_STRUCT_VERSION_TS103000_REV1:
|
||||
case REPLAY_STRUCT_VERSION_TS103000_REV2:
|
||||
case REPLAY_STRUCT_VERSION_TS103000_REV3:
|
||||
case REPLAY_STRUCT_VERSION_TS104000_REV0:
|
||||
{
|
||||
if(taisei_version_read(file, &rpy->game_version) != TAISEI_VERSION_SIZE) {
|
||||
log_error("%s: Failed to read game version", source);
|
||||
|
@ -485,6 +508,14 @@ static bool _replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize, co
|
|||
CHECKPROP(stg->plr_points_final = SDL_ReadLE64(file), zu);
|
||||
}
|
||||
|
||||
if(version >= REPLAY_STRUCT_VERSION_TS104000_REV0) {
|
||||
CHECKPROP(stg->plr_stats_total_lives_used = SDL_ReadU8(file), u);
|
||||
CHECKPROP(stg->plr_stats_stage_lives_used = SDL_ReadU8(file), u);
|
||||
CHECKPROP(stg->plr_stats_total_bombs_used = SDL_ReadU8(file), u);
|
||||
CHECKPROP(stg->plr_stats_stage_bombs_used = SDL_ReadU8(file), u);
|
||||
CHECKPROP(stg->plr_stats_stage_continues_used = SDL_ReadU8(file), u);
|
||||
}
|
||||
|
||||
CHECKPROP(stg->num_events = SDL_ReadLE16(file), u);
|
||||
|
||||
if(replay_calc_stageinfo_checksum(stg, version) + SDL_ReadLE32(file)) {
|
||||
|
|
13
src/replay.h
13
src/replay.h
|
@ -54,13 +54,16 @@
|
|||
|
||||
// Taisei v1.3 revision 3: add final score at the end of each stage
|
||||
#define REPLAY_STRUCT_VERSION_TS103000_REV3 12
|
||||
|
||||
// Taisei v1.4 revision 0: add statistics for player
|
||||
#define REPLAY_STRUCT_VERSION_TS104000_REV0 13
|
||||
/* END supported struct versions */
|
||||
|
||||
#define REPLAY_VERSION_COMPRESSION_BIT 0x8000
|
||||
#define REPLAY_COMPRESSION_CHUNK_SIZE 4096
|
||||
|
||||
// What struct version to use when saving recorded replays
|
||||
#define REPLAY_STRUCT_VERSION_WRITE (REPLAY_STRUCT_VERSION_TS103000_REV3 | REPLAY_VERSION_COMPRESSION_BIT)
|
||||
#define REPLAY_STRUCT_VERSION_WRITE (REPLAY_STRUCT_VERSION_TS104000_REV0 | REPLAY_VERSION_COMPRESSION_BIT)
|
||||
|
||||
#define REPLAY_ALLOC_INITIAL 256
|
||||
|
||||
|
@ -130,6 +133,14 @@ typedef struct ReplayStage {
|
|||
uint64_t plr_points_final;
|
||||
/* END REPLAY_STRUCT_VERSION_TS102000_REV3 and above */
|
||||
|
||||
/* BEGIN REPLAY_STRUCT_VERSION_TS104000_REV0 and above */
|
||||
uint8_t plr_stats_total_lives_used;
|
||||
uint8_t plr_stats_stage_lives_used;
|
||||
uint8_t plr_stats_total_bombs_used;
|
||||
uint8_t plr_stats_stage_bombs_used;
|
||||
uint8_t plr_stats_stage_continues_used;
|
||||
/* END REPLAY_STRUCT_VERSION_TS104000_REV0 and above */
|
||||
|
||||
// player input
|
||||
// NOTE: only used to read the number of events from file.
|
||||
// Actual numbers of events stored/allocated are tracked by the .events dynamic array.
|
||||
|
|
|
@ -214,6 +214,8 @@ static void stage_start(StageInfo *stage) {
|
|||
|
||||
player_stage_pre_init(&global.plr);
|
||||
|
||||
stats_stage_reset(&global.plr.stats);
|
||||
|
||||
if(stage->type == STAGE_SPELL) {
|
||||
global.is_practice_mode = true;
|
||||
global.plr.lives = 0;
|
||||
|
@ -1051,7 +1053,7 @@ void stage_end_loop(void* ctx) {
|
|||
}
|
||||
|
||||
void stage_unlock_bgm(const char *bgm) {
|
||||
if(global.replaymode != REPLAY_PLAY && !global.plr.continues_used) {
|
||||
if(global.replaymode != REPLAY_PLAY && !global.plr.stats.total.continues_used) {
|
||||
progress_unlock_bgm(bgm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,16 +187,6 @@ void stagetext_table_add_separator(StageTextTable *tbl) {
|
|||
tbl->pos += I * 0.5 * font_get_lineskip(get_font("standard"));
|
||||
}
|
||||
|
||||
void stagetext_table_test(void) {
|
||||
StageTextTable tbl;
|
||||
stagetext_begin_table(&tbl, "Test", RGB(1, 1, 1), RGB(1, 1, 1), VIEWPORT_W/2, 60, 300, 30, 60);
|
||||
stagetext_table_add(&tbl, "foo", "bar");
|
||||
stagetext_table_add(&tbl, "qwerty", "asdfg");
|
||||
stagetext_table_add(&tbl, "top", "kek");
|
||||
stagetext_table_add_separator(&tbl);
|
||||
stagetext_table_add_numeric(&tbl, "Total Score", 9000000);
|
||||
stagetext_end_table(&tbl);
|
||||
}
|
||||
|
||||
StageText *stagetext_list_head(void) {
|
||||
return textlist;
|
||||
|
|
|
@ -75,6 +75,4 @@ void stagetext_table_add_numeric(StageTextTable *tbl, const char *title, int n);
|
|||
void stagetext_table_add_numeric_nonzero(StageTextTable *tbl, const char *title, int n);
|
||||
void stagetext_table_add_separator(StageTextTable *tbl);
|
||||
|
||||
void stagetext_table_test(void);
|
||||
|
||||
#endif // IGUARD_stagetext_h
|
||||
|
|
45
src/stats.c
Normal file
45
src/stats.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
|
||||
#include "stats.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "log.h"
|
||||
|
||||
void stats_init(Stats *stats) {
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
}
|
||||
|
||||
void stats_track_life_used(Stats *stats) {
|
||||
stats->total.lives_used++;
|
||||
stats->stage.lives_used++;
|
||||
log_debug("lives used (total): %d", stats->total.lives_used);
|
||||
log_debug("lives used (stage): %d", stats->stage.lives_used);
|
||||
}
|
||||
|
||||
void stats_track_bomb_used(Stats *stats) {
|
||||
stats->total.bombs_used++;
|
||||
stats->stage.bombs_used++;
|
||||
log_debug("bombs used (total): %d", stats->total.bombs_used);
|
||||
log_debug("bombs used (stage): %d", stats->stage.bombs_used);
|
||||
}
|
||||
|
||||
void stats_track_continue_used(Stats *stats) {
|
||||
stats->total.continues_used++;
|
||||
stats->stage.continues_used++;
|
||||
log_debug("bombs used (total): %d", stats->total.continues_used);
|
||||
log_debug("bombs used (stage): %d", stats->stage.continues_used);
|
||||
}
|
||||
|
||||
void stats_stage_reset(Stats *stats) {
|
||||
memset(&stats->stage, 0, sizeof(stats->stage));
|
||||
log_debug("statistics reset");
|
||||
}
|
32
src/stats.h
Normal file
32
src/stats.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_stats_h
|
||||
#define IGUARD_stats_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
typedef struct Stats Stats;
|
||||
|
||||
struct Stats {
|
||||
struct {
|
||||
int lives_used;
|
||||
int bombs_used;
|
||||
int continues_used;
|
||||
} total, stage;
|
||||
};
|
||||
|
||||
void stats_init(Stats *stats);
|
||||
|
||||
void stats_track_life_used(Stats *stats);
|
||||
void stats_track_bomb_used(Stats *stats);
|
||||
void stats_track_continue_used(Stats *stats);
|
||||
|
||||
void stats_stage_reset(Stats *stats);
|
||||
|
||||
#endif // IGUARD_stats_h
|
Loading…
Reference in a new issue