add optional floating scoring text

This commit is contained in:
Andrei Alexeyev 2019-04-07 01:55:13 +03:00
parent 649ef31ce5
commit 488ff43f85
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
12 changed files with 98 additions and 32 deletions

View file

@ -826,7 +826,7 @@ static void boss_give_spell_bonus(Boss *boss, Attack *a, Player *plr) {
char diff_bonus_text[6];
snprintf(diff_bonus_text, sizeof(diff_bonus_text), "x%.2f", bonus.diff_multiplier);
player_add_points(plr, bonus.total);
player_add_points(plr, bonus.total, plr->pos);
StageTextTable tbl;
stagetext_begin_table(&tbl, title, RGB(1, 1, 1), RGB(1, 1, 1), VIEWPORT_W/2, 0,

View file

@ -113,6 +113,7 @@
CONFIGDEF_INT (POSTPROCESS, "postprocess", 2) \
CONFIGDEF_INT (HEALTHBAR_STYLE, "healthbar_style", 1) \
CONFIGDEF_INT (SKIP_SPEED, "skip_speed", 10) \
CONFIGDEF_FLOAT (SCORETEXT_ALPHA, "scoretext_alpha", 1) \
KEYDEFS \
CONFIGDEF_INT (GAMEPAD_ENABLED, "gamepad_enabled", 1) \
CONFIGDEF_STRING (GAMEPAD_DEVICE, "gamepad_device", "default") \

View file

@ -240,31 +240,31 @@ void process_items(void) {
switch(item->type) {
case ITEM_POWER:
player_add_power(&global.plr, POWER_VALUE);
player_add_points(&global.plr, 25);
player_add_points(&global.plr, 25, item->pos);
player_extend_powersurge(&global.plr, PLR_POWERSURGE_POSITIVE_GAIN*3, PLR_POWERSURGE_NEGATIVE_GAIN*3);
play_sound("item_generic");
break;
case ITEM_POWER_MINI:
player_add_power(&global.plr, POWER_VALUE_MINI);
player_add_points(&global.plr, 5);
player_add_points(&global.plr, 5, item->pos);
play_sound("item_generic");
break;
case ITEM_SURGE:
player_extend_powersurge(&global.plr, PLR_POWERSURGE_POSITIVE_GAIN, PLR_POWERSURGE_NEGATIVE_GAIN);
player_add_points(&global.plr, 25);
player_add_points(&global.plr, 25, item->pos);
play_sound("item_generic");
break;
case ITEM_POINTS:
player_add_points(&global.plr, round(global.plr.point_item_value * item->pickup_value));
player_add_points(&global.plr, round(global.plr.point_item_value * item->pickup_value), item->pos);
play_sound("item_generic");
break;
case ITEM_PIV:
player_add_piv(&global.plr, 1);
player_add_piv(&global.plr, 1, item->pos);
play_sound("item_generic");
break;
case ITEM_VOLTAGE:
player_add_voltage(&global.plr, 1);
player_add_piv(&global.plr, 10);
player_add_piv(&global.plr, 10, item->pos);
play_sound("item_generic");
break;
case ITEM_LIFE:

View file

@ -793,6 +793,10 @@ MenuData* create_options_menu(void) {
); bind_addvalue(b, "classic");
bind_addvalue(b, "modern");
add_menu_entry(m, "Floating score text visibility", do_nothing,
b = bind_scale(CONFIG_SCORETEXT_ALPHA, 0, 1, 0.05)
);
add_menu_separator(m);
add_menu_entry(m, "SFX Volume", do_nothing,

View file

@ -614,7 +614,7 @@ static void player_powersurge_expired(Player *plr) {
.angle = M_PI*2*frand(),
);
player_add_points(&global.plr, bonus.score);
player_add_points(&global.plr, bonus.score, plr->pos);
ent_area_damage(plr->pos, bonus.discharge_range, &(DamageInfo) { bonus.discharge_damage, DMG_PLAYER_DISCHARGE }, NULL, NULL);
stage_clear_hazards_at(plr->pos, bonus.discharge_range, CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW | CLEAR_HAZARDS_SPAWN_VOLTAGE);
@ -1181,7 +1181,7 @@ void player_graze(Player *plr, complex pos, int pts, int effect_intensity, const
pos = (pos + plr->pos) * 0.5;
player_add_points(plr, pts);
player_add_points(plr, pts, pos);
play_sound("graze");
Color *c = COLOR_COPY(color);
@ -1215,7 +1215,7 @@ static void player_add_fragments(Player *plr, int frags, int *pwhole, int *pfrag
int excess_frags = total_frags + frags - maxwhole * maxfrags;
if(excess_frags > 0) {
player_add_points(plr, excess_frags * score_per_excess);
player_add_points(plr, excess_frags * score_per_excess, plr->pos);
frags -= excess_frags;
}
@ -1285,16 +1285,40 @@ void player_add_bombs(Player *plr, int bombs) {
player_add_bomb_fragments(plr, PLR_MAX_BOMB_FRAGMENTS);
}
void player_add_points(Player *plr, uint points) {
static void scoretext_predraw(StageText *txt, int t, float a) {
float r = bits_to_float((uintptr_t)txt->custom.data1);
txt->pos -= I * cexp(I*r) * a;
}
static float scoreval_importance(Player *plr, uint points) {
return clamp((double)points / (double)plr->point_item_value, 0, 1);
}
void player_add_points(Player *plr, uint points, complex location) {
plr->points += points;
while(plr->points >= plr->extralife_threshold) {
plr->extralife_threshold = player_next_extralife_threshold(++plr->extralives_given);
player_add_lives(plr, 1);
}
float rnd = nfrand();
float imp = scoreval_importance(plr, points);
float a = clamp((0.5 + 0.5 * cbrtf(imp)) * config_get_float(CONFIG_SCORETEXT_ALPHA), 0, 1);
if(a < 1e-4) {
return;
}
char buf[64];
format_huge_num(0, points, sizeof(buf), buf);
Color *c = color_mul_scalar(color_lerp(RGB(1.0, 0.8, 0.4), RGB(0.4, 1.0, 0.3), imp), a);
StageText *t = stagetext_add(buf, location, ALIGN_CENTER, get_font("small"), c, 0, 25 + 20 * imp, 10, 20);
t->custom.data1 = (void*)(uintptr_t)float_to_bits(rnd);
t->custom.predraw = scoretext_predraw;
}
void player_add_piv(Player *plr, uint piv) {
void player_add_piv(Player *plr, uint piv, complex location) {
uint v = plr->point_item_value + piv;
if(v > PLR_MAX_PIV || v < plr->point_item_value) {
@ -1302,6 +1326,21 @@ void player_add_piv(Player *plr, uint piv) {
} else {
plr->point_item_value = v;
}
float rnd = nfrand();
float a = clamp((0.5 + 0.5 * min(piv/10.0, 1)) * config_get_float(CONFIG_SCORETEXT_ALPHA), 0, 1);
if(a < 1e-4) {
return;
}
char buf[64];
format_huge_num(0, piv, sizeof(buf), buf);
strcat(buf, "v");
Color *c = color_mul_scalar(RGB(0.5, 0.8, 1.0), a);
StageText *t = stagetext_add(buf, location, ALIGN_CENTER, get_font("small"), c, 0, 35, 10, 20);
t->custom.data1 = (void*)(uintptr_t)float_to_bits(rnd);
t->custom.predraw = scoretext_predraw;
}
void player_add_voltage(Player *plr, uint voltage) {
@ -1338,14 +1377,14 @@ void player_register_damage(Player *plr, EntityInterface *target, const DamageIn
if(target != NULL) {
switch(target->type) {
case ENT_ENEMY: {
player_add_points(&global.plr, damage->amount * 0.5);
pos = ENT_CAST(target, Enemy)->pos;
player_add_points(&global.plr, damage->amount * 0.5, pos);
break;
}
case ENT_BOSS: {
player_add_points(&global.plr, damage->amount * 0.2);
pos = ENT_CAST(target, Boss)->pos;
player_add_points(&global.plr, damage->amount * 0.2, pos);
break;
}

View file

@ -201,8 +201,8 @@ void player_add_life_fragments(Player *plr, int frags);
void player_add_bomb_fragments(Player *plr, int frags);
void player_add_lives(Player *plr, int lives);
void player_add_bombs(Player *plr, int bombs);
void player_add_points(Player *plr, uint points);
void player_add_piv(Player *plr, uint piv);
void player_add_points(Player *plr, uint points, complex location);
void player_add_piv(Player *plr, uint piv, complex location);
void player_add_voltage(Player *plr, uint voltage);
bool player_drain_voltage(Player *plr, uint voltage);
void player_extend_powersurge(Player *plr, float pos, float neg);

View file

@ -715,7 +715,7 @@ static void stage_give_clear_bonus(const StageInfo *stage, StageClearBonus *bonu
// TODO: maybe a difficulty multiplier?
bonus->total = bonus->base + bonus->voltage + bonus->lives;
player_add_points(&global.plr, bonus->total);
player_add_points(&global.plr, bonus->total, global.plr.pos);
}
static LogicFrameAction stage_logic_frame(void *arg) {

View file

@ -13,18 +13,21 @@
#include "item.h"
#include "enemy.h"
#include "laser.h"
#include "stagetext.h"
#include "aniplayer.h"
#define MAX_projectiles 1024
#define MAX_items MAX_projectiles
#define MAX_enemies 64
#define MAX_lasers 64
#define MAX_stagetext 128
#define OBJECT_POOLS \
OBJECT_POOL(Projectile, projectiles) \
OBJECT_POOL(Item, items) \
OBJECT_POOL(Enemy, enemies) \
OBJECT_POOL(Laser, lasers) \
OBJECT_POOL(StageText, stagetext) \
StageObjectPools stage_object_pools;

View file

@ -20,6 +20,7 @@ typedef struct StageObjectPools {
ObjectPool *items;
ObjectPool *enemies;
ObjectPool *lasers;
ObjectPool *stagetext;
};
ObjectPool *first;

View file

@ -17,10 +17,14 @@ static StageText *textlist = NULL;
#define NUM_PLACEHOLDER "........................"
StageText* stagetext_add(const char *text, complex pos, Alignment align, Font *font, const Color *clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
StageText *t = malloc(sizeof(StageText));
StageText *t = (StageText*)objpool_acquire(stage_object_pools.stagetext);
list_append(&textlist, t);
t->text = strdup(text);
if(text != NULL) {
assert(strlen(text) < sizeof(t->text));
strcpy(t->text, text);
}
t->font = font;
t->pos = pos;
t->align = align;
@ -31,8 +35,6 @@ StageText* stagetext_add(const char *text, complex pos, Alignment align, Font *f
t->time.fadeout = fadeouttime;
t->time.life = lifetime + fadeouttime;
memset(&t->custom, 0, sizeof(t->custom));
return t;
}
@ -49,8 +51,7 @@ StageText* stagetext_add_numeric(int n, complex pos, Alignment align, Font *font
}
static void* stagetext_delete(List **dest, List *txt, void *arg) {
free(((StageText*)txt)->text);
free(list_unlink(dest, txt));
objpool_release(stage_object_pools.stagetext, (ObjectInterface*)list_unlink(dest, txt));
return NULL;
}

View file

@ -13,6 +13,7 @@
#include "util.h"
#include "color.h"
#include "objectpool.h"
#include "resource/font.h"
typedef struct StageText StageText;
@ -21,15 +22,23 @@ typedef void (*StageTextPreDrawFunc)(StageText* txt, int t, float alpha);
typedef struct StageTextTable StageTextTable;
// NOTE: tweaked to consume all padding in StageText, assuming x86_64 ABI
#define STAGETEXT_BUF_SIZE 76
struct StageText {
LIST_INTERFACE(StageText);
OBJECT_INTERFACE(StageText);
char *text;
Font *font;
complex pos;
Alignment align;
struct {
StageTextPreDrawFunc predraw;
void *data1;
void *data2;
} custom;
Color color;
Alignment align;
struct {
int spawn;
@ -38,11 +47,7 @@ struct StageText {
int fadeout;
} time;
struct {
StageTextPreDrawFunc predraw;
void *data1;
void *data2;
} custom;
char text[STAGETEXT_BUF_SIZE];
};
void stagetext_free(void);

View file

@ -17,6 +17,18 @@ void* memdup(const void *src, size_t size);
void inherit_missing_pointers(uint num, void *dest[num], void *const base[num]);
bool is_main_thread(void);
static inline attr_must_inline uint32_t float_to_bits(float f) {
union { uint32_t i; float f; } u;
u.f = f;
return u.i;
}
static inline attr_must_inline float bits_to_float(uint32_t i) {
union { uint32_t i; float f; } u;
u.i = i;
return u.f;
}
extern SDL_threadID main_thread_id;
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr)))