taisei/src/player.c

1510 lines
37 KiB
C
Raw Normal View History

/*
* 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@alienslab.net>.
*/
#include "taisei.h"
#include "player.h"
#include "projectile.h"
#include "global.h"
#include "plrmodes.h"
#include "stage.h"
2017-09-16 03:15:34 +02:00
#include "stagetext.h"
#include "stagedraw.h"
#include "entity.h"
void player_init(Player *plr) {
memset(plr, 0, sizeof(Player));
plr->pos = PLR_SPAWN_POS;
plr->lives = PLR_START_LIVES;
plr->bombs = PLR_START_BOMBS;
plr->point_item_value = PLR_START_PIV;
plr->power = 100;
plr->deathtime = -1;
plr->continuetime = -1;
plr->mode = plrmode_find(0, 0);
}
void player_stage_pre_init(Player *plr) {
plr->recovery = 0;
plr->respawntime = 0;
plr->deathtime = -1;
plr->axis_lr = 0;
plr->axis_ud = 0;
plrmode_preload(plr->mode);
}
double player_property(Player *plr, PlrProperty prop) {
return plr->mode->procs.property(plr, prop);
}
static void ent_draw_player(EntityInterface *ent);
2018-07-30 09:04:09 +02:00
static DamageResult ent_damage_player(EntityInterface *ent, const DamageInfo *dmg);
static void player_spawn_focus_circle(Player *plr);
void player_stage_post_init(Player *plr) {
assert(plr->mode != NULL);
// ensure the essential callbacks are there. other code tests only for the optional ones
assert(plr->mode->procs.shot != NULL);
assert(plr->mode->procs.bomb != NULL);
assert(plr->mode->procs.property != NULL);
2018-07-15 17:48:22 +02:00
assert(plr->mode->character != NULL);
assert(plr->mode->dialog != NULL);
2017-10-24 04:57:14 +02:00
delete_enemies(&global.plr.slaves);
if(plr->mode->procs.init != NULL) {
plr->mode->procs.init(plr);
}
aniplayer_create(&plr->ani, get_ani(plr->mode->character->player_sprite_name), "main");
plr->ent.draw_layer = LAYER_PLAYER;
plr->ent.draw_func = ent_draw_player;
2018-07-30 09:04:09 +02:00
plr->ent.damage_func = ent_damage_player;
ent_register(&plr->ent, ENT_PLAYER);
player_spawn_focus_circle(plr);
plr->extralife_threshold = player_next_extralife_threshold(plr->extralives_given);
while(plr->points >= plr->extralife_threshold) {
plr->extralife_threshold = player_next_extralife_threshold(++plr->extralives_given);
}
}
2017-11-25 16:51:43 +01:00
void player_free(Player *plr) {
if(plr->mode->procs.free) {
plr->mode->procs.free(plr);
}
2018-05-08 18:17:18 +02:00
aniplayer_free(&plr->ani);
ent_unregister(&plr->ent);
delete_enemy(&plr->focus_circle, plr->focus_circle.first);
2017-11-25 16:51:43 +01:00
}
static void player_full_power(Player *plr) {
play_sound("full_power");
stage_clear_hazards(CLEAR_HAZARDS_ALL);
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
stagetext_add("Full Power!", VIEWPORT_W * 0.5 + VIEWPORT_H * 0.33 * I, ALIGN_CENTER, get_font("big"), RGB(1, 1, 1), 0, 60, 20, 20);
}
2017-10-24 04:57:14 +02:00
bool player_set_power(Player *plr, short npow) {
int pow_base = clamp(npow, 0, PLR_MAX_POWER);
int pow_overflow = clamp(npow - PLR_MAX_POWER, 0, PLR_MAX_POWER_OVERFLOW);
2017-03-30 17:11:21 +02:00
if(plr->mode->procs.power) {
plr->mode->procs.power(plr, pow_base);
}
int oldpow = plr->power;
int oldpow_over = plr->power_overflow;
plr->power = pow_base;
plr->power_overflow = pow_overflow;
if((oldpow + oldpow_over) / 100 < (pow_base + pow_overflow) / 100) {
2017-12-26 04:18:57 +01:00
play_sound("powerup");
}
2017-10-24 04:57:14 +02:00
if(plr->power == PLR_MAX_POWER && oldpow < PLR_MAX_POWER) {
player_full_power(plr);
}
return (oldpow + oldpow_over) != (plr->power + plr->power_overflow);
}
bool player_add_power(Player *plr, short pdelta) {
return player_set_power(plr, plr->power + plr->power_overflow + pdelta);
}
2012-07-20 16:11:24 +02:00
void player_move(Player *plr, complex delta) {
delta *= player_property(plr, PLR_PROP_SPEED);
complex lastpos = plr->pos;
double x = clamp(creal(plr->pos) + creal(delta), PLR_MIN_BORDER_DIST, VIEWPORT_W - PLR_MIN_BORDER_DIST);
double y = clamp(cimag(plr->pos) + cimag(delta), PLR_MIN_BORDER_DIST, VIEWPORT_H - PLR_MIN_BORDER_DIST);
plr->pos = x + y*I;
complex realdir = plr->pos - lastpos;
if(cabs(realdir)) {
plr->lastmovedir = realdir / cabs(realdir);
}
plr->velocity = realdir;
2011-07-05 15:20:19 +02:00
}
static void ent_draw_player(EntityInterface *ent) {
Player *plr = ENT_CAST(ent, Player);
if(plr->deathtime >= global.frames) {
2018-05-19 01:24:49 +02:00
return;
}
if(plr->focus) {
r_draw_sprite(&(SpriteParams) {
.sprite = "fairy_circle",
.rotation.angle = DEG2RAD * global.frames * 10,
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
.color = RGBA_MUL_ALPHA(1, 1, 1, 0.2 * (clamp(plr->focus, 0, 15) / 15.0)),
.pos = { creal(plr->pos), cimag(plr->pos) },
});
}
Color c;
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
if(!player_is_vulnerable(plr)) {
float f = 0.3*sin(0.1*global.frames);
c = *RGBA_MUL_ALPHA(1.0+f, 1.0, 1.0-f, 0.7+f);
} else {
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
c = *RGBA_MUL_ALPHA(1.0, 1.0, 1.0, 1.0);
}
r_draw_sprite(&(SpriteParams) {
.sprite_ptr = aniplayer_get_frame(&plr->ani),
.pos = { creal(plr->pos), cimag(plr->pos) },
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
.color = &c,
});
}
static int player_focus_circle_logic(Enemy *e, int t) {
if(t < 0) {
return ACTION_NONE;
}
double alpha = creal(e->args[0]);
if(t <= 1) {
alpha = min(0.1, alpha);
} else {
alpha = approach(alpha, (global.plr.inputflags & INFLAG_FOCUS) ? 1 : 0, 1/30.0);
}
e->args[0] = alpha;
return ACTION_NONE;
}
static void player_focus_circle_visual(Enemy *e, int t, bool render) {
if(!render) {
return;
}
float focus_opacity = creal(e->args[0]);
if(focus_opacity > 0) {
int trans_frames = 12;
double trans_factor = 1 - min(trans_frames, t) / (double)trans_frames;
double rot_speed = DEG2RAD * global.frames * (1 + 3 * trans_factor);
double scale = 1.0 + trans_factor;
r_draw_sprite(&(SpriteParams) {
.sprite = "focus",
.rotation.angle = rot_speed,
.color = RGBA_MUL_ALPHA(1, 1, 1, creal(e->args[0])),
.pos = { creal(e->pos), cimag(e->pos) },
.scale.both = scale,
});
r_draw_sprite(&(SpriteParams) {
.sprite = "focus",
.rotation.angle = rot_speed * -1,
.color = RGBA_MUL_ALPHA(1, 1, 1, creal(e->args[0])),
.pos = { creal(e->pos), cimag(e->pos) },
.scale.both = scale,
});
}
float ps_opacity = 1.0;
float ps_fill_factor = 1.0;
if(player_is_powersurge_active(&global.plr)) {
ps_opacity *= clamp((global.frames - global.plr.powersurge.time.activated) / 30.0, 0, 1);
} else if(global.plr.powersurge.time.expired == 0) {
ps_opacity = 0;
} else {
ps_opacity *= (1 - clamp((global.frames - global.plr.powersurge.time.expired) / 40.0, 0, 1));
ps_fill_factor = pow(ps_opacity, 2);
}
if(ps_opacity > 0) {
r_state_push();
r_mat_push();
r_mat_translate(creal(e->pos), cimag(e->pos), 0);
r_mat_scale(140, 140, 0);
r_shader("healthbar_radial");
r_uniform_vec4_rgba("borderColor", RGBA(0.5, 0.5, 0.5, 0.5));
r_uniform_vec4_rgba("glowColor", RGBA(0.5, 0.5, 0.5, 0.75));
r_uniform_vec4_rgba("fillColor", RGBA(1.5, 0.5, 0.0, 0.75));
r_uniform_vec4_rgba("altFillColor", RGBA(0.0, 0.5, 1.5, 0.75));
r_uniform_vec4_rgba("coreFillColor", RGBA(0.8, 0.8, 0.8, 0.25));
r_uniform_vec2("fill", global.plr.powersurge.positive * ps_fill_factor, global.plr.powersurge.negative * ps_fill_factor);
r_uniform_float("opacity", ps_opacity);
r_draw_quad();
r_mat_pop();
r_state_pop();
char buf[64];
format_huge_num(0, global.plr.powersurge.bonus.baseline, sizeof(buf), buf);
Font *fnt = get_font("monotiny");
float x = creal(e->pos);
float y = cimag(e->pos) + 80;
float text_opacity = ps_opacity * 0.75;
x += text_draw(buf, &(TextParams) {
.shader = "text_hud",
.font_ptr = fnt,
.pos = { x, y },
.color = RGBA_MUL_ALPHA(1.0, 1.0, 1.0, text_opacity),
.align = ALIGN_CENTER,
});
snprintf(buf, sizeof(buf), " +%u", global.plr.powersurge.bonus.gain_rate);
text_draw(buf, &(TextParams) {
.shader = "text_hud",
.font_ptr = fnt,
.pos = { x, y },
.color = RGBA_MUL_ALPHA(0.3, 0.6, 1.0, text_opacity),
.align = ALIGN_LEFT,
});
r_shader("sprite_filled_circle");
r_uniform_vec4("color_inner", 0, 0, 0, 0);
r_uniform_vec4("color_outer", 0, 0, 0.1 * ps_opacity, 0.1 * ps_opacity);
}
}
static void player_spawn_focus_circle(Player *plr) {
Enemy *f = create_enemy_p(&plr->focus_circle, 0, ENEMY_IMMUNE, player_focus_circle_visual, player_focus_circle_logic, 0, 0, 0, 0);
f->ent.draw_layer = LAYER_PLAYER_FOCUS;
}
2017-04-04 02:57:38 +02:00
static void player_fail_spell(Player *plr) {
if( !global.boss ||
2017-04-04 02:57:38 +02:00
!global.boss->current ||
global.boss->current->finished ||
global.boss->current->failtime ||
global.boss->current->starttime >= global.frames ||
2017-04-04 02:57:38 +02:00
global.stage->type == STAGE_SPELL
) {
return;
}
global.boss->current->failtime = global.frames;
if(global.boss->current->type == AT_ExtraSpell) {
boss_finish_current_attack(global.boss);
}
}
bool player_should_shoot(Player *plr, bool extra) {
return
(plr->inputflags & INFLAG_SHOT) &&
!global.dialog
&& player_is_alive(&global.plr)
/* && (!extra || !player_is_bomb_active(plr)) */;
}
void player_placeholder_bomb_logic(Player *plr) {
if(!player_is_bomb_active(plr)) {
return;
}
DamageInfo dmg;
dmg.amount = 100;
dmg.type = DMG_PLAYER_BOMB;
for(Enemy *en = global.enemies.first; en; en = en->next) {
ent_damage(&en->ent, &dmg);
}
if(global.boss) {
ent_damage(&global.boss->ent, &dmg);
}
stage_clear_hazards(CLEAR_HAZARDS_ALL);
}
static void player_powersurge_expired(Player *plr);
static void _powersurge_trail_draw(Projectile *p, float t, float cmul) {
float nt = t / p->timeout;
float s = 1 + (2 + 0.5 * psin((t+global.frames*1.23)/5.0)) * nt * nt;
r_draw_sprite(&(SpriteParams) {
.sprite_ptr = p->sprite,
.scale.both = s,
.pos = { creal(p->pos), cimag(p->pos) },
.color = color_mul_scalar(RGBA(0.8, 0.1 + 0.2 * psin((t+global.frames)/5.0), 0.1, 0.0), 0.5 * (1 - nt) * cmul),
.shader_params = &(ShaderCustomParams){{ -2 * nt * nt }},
.shader = "sprite_silhouette",
});
}
static void powersurge_trail_draw(Projectile *p, int t) {
if(t > 0) {
_powersurge_trail_draw(p, t - 0.5, 0.25);
_powersurge_trail_draw(p, t, 0.25);
} else {
_powersurge_trail_draw(p, t, 0.5);
}
}
static int powersurge_trail(Projectile *p, int t) {
if(t == EVENT_BIRTH) {
return ACTION_ACK;
}
if(t == EVENT_DEATH) {
free(p->sprite);
return ACTION_ACK;
}
complex v = (global.plr.pos - p->pos) * 0.05;
p->args[0] += (v - p->args[0]) * (1 - t / p->timeout);
p->pos += p->args[0];
return ACTION_NONE;
}
void player_powersurge_calc_bonus(Player *plr, PowerSurgeBonus *b) {
b->gain_rate = round(1000 * plr->powersurge.negative * plr->powersurge.negative);
b->baseline = plr->powersurge.power + plr->powersurge.damage_done * 0.4;
b->score = b->baseline;
b->discharge_power = sqrtf(0.2 * b->baseline + 1024 * log1pf(b->baseline)) * smoothstep(0, 1, 0.0001 * b->baseline);
b->discharge_range = 1.2 * b->discharge_power;
b->discharge_damage = 10 * pow(b->discharge_power, 1.1);
}
static int powersurge_charge_particle(Projectile *p, int t) {
if(t == EVENT_BIRTH) {
return ACTION_ACK;
}
if(t == EVENT_DEATH) {
return ACTION_ACK;
}
Player *plr = &global.plr;
if(player_is_alive(plr)) {
p->pos = plr->pos;
}
return ACTION_NONE;
}
static void player_powersurge_logic(Player *plr) {
if(global.dialog) {
return;
}
plr->powersurge.positive = max(0, plr->powersurge.positive - lerp(PLR_POWERSURGE_POSITIVE_DRAIN_MIN, PLR_POWERSURGE_POSITIVE_DRAIN_MAX, plr->powersurge.positive));
plr->powersurge.negative = max(0, plr->powersurge.negative - lerp(PLR_POWERSURGE_NEGATIVE_DRAIN_MIN, PLR_POWERSURGE_NEGATIVE_DRAIN_MAX, plr->powersurge.negative));
if(stage_is_cleared()) {
player_cancel_powersurge(plr);
return;
}
if(plr->powersurge.positive <= plr->powersurge.negative) {
player_powersurge_expired(plr);
return;
}
player_powersurge_calc_bonus(plr, &plr->powersurge.bonus);
PARTICLE(
.sprite_ptr = memdup(aniplayer_get_frame(&plr->ani), sizeof(Sprite)),
.pos = plr->pos,
.color = RGBA(1, 1, 1, 0.5),
.rule = powersurge_trail,
.draw_rule = powersurge_trail_draw,
.timeout = 15,
.layer = LAYER_PARTICLE_HIGH,
.flags = PFLAG_NOREFLECT,
);
if(!(global.frames % 6)) {
Sprite *spr = get_sprite("part/powersurge_field");
double scale = 2 * plr->powersurge.bonus.discharge_range / spr->w;
double angle = frand() * 2 * M_PI;
PARTICLE(
.sprite_ptr = spr,
.pos = plr->pos,
.color = color_mul_scalar(frand() < 0.5 ? RGBA(1.5, 0.5, 0.0, 0.1) : RGBA(0.0, 0.5, 1.5, 0.1), 0.25),
.rule = powersurge_charge_particle,
.draw_rule = ScaleFade,
.timeout = 14,
.angle = angle,
.args = { 0, 0, (1+I)*scale, 0},
.layer = LAYER_PLAYER - 1,
.flags = PFLAG_NOREFLECT,
);
PARTICLE(
.sprite_ptr = spr,
.pos = plr->pos,
.color = RGBA(0.5, 0.5, 0.5, 0),
.rule = powersurge_charge_particle,
.draw_rule = ScaleFade,
.timeout = 3,
.angle = angle,
.args = { 0, 0, (1+I)*scale, 0},
.layer = LAYER_PLAYER - 1,
.flags = PFLAG_NOREFLECT,
);
}
plr->powersurge.power += plr->powersurge.bonus.gain_rate;
}
void player_logic(Player* plr) {
if(plr->continuetime == global.frames) {
plr->lives = PLR_START_LIVES;
plr->bombs = PLR_START_BOMBS;
plr->point_item_value = PLR_START_PIV;
plr->life_fragments = 0;
plr->bomb_fragments = 0;
plr->continues_used += 1;
2017-10-31 07:58:49 +01:00
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));
}
2011-07-05 15:20:19 +02:00
process_enemies(&plr->slaves);
2017-10-03 17:25:38 +02:00
aniplayer_update(&plr->ani);
if(plr->respawntime > global.frames) {
double x = PLR_SPAWN_POS_X;
double y = lerp(PLR_SPAWN_POS_Y, VIEWPORT_H + 64, smoothstep(0.0, 1.0, (plr->respawntime - global.frames) / (double)PLR_RESPAWN_TIME));
plr->pos = CMPLX(x, y);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
2011-07-04 14:10:12 +02:00
return;
}
2012-08-11 14:24:58 +02:00
if(player_is_powersurge_active(plr)) {
player_powersurge_logic(plr);
}
plr->focus = approach(plr->focus, (plr->inputflags & INFLAG_FOCUS) ? 30 : 0, 1);
plr->focus_circle.first->pos = plr->pos;
process_enemies(&plr->focus_circle);
if(plr->mode->procs.think) {
plr->mode->procs.think(plr);
}
if(player_should_shoot(plr, false)) {
plr->mode->procs.shot(plr);
2012-08-03 17:06:25 +02:00
}
if(global.frames == plr->deathtime) {
2012-07-20 16:11:24 +02:00
player_realdeath(plr);
} else if(plr->deathtime > global.frames) {
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
}
2012-08-11 14:24:58 +02:00
if(player_is_bomb_active(plr)) {
if(plr->bombcanceltime) {
int bctime = plr->bombcanceltime + plr->bombcanceldelay;
if(bctime <= global.frames) {
plr->recovery = global.frames;
plr->bombcanceltime = 0;
plr->bombcanceldelay = 0;
return;
}
}
2017-04-04 02:57:38 +02:00
player_fail_spell(plr);
2011-11-01 21:20:40 +01:00
}
}
static bool player_bomb(Player *plr) {
if(global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell)
return false;
int bomb_time = floor(player_property(plr, PLR_PROP_BOMB_TIME));
if(bomb_time <= 0) {
return false;
}
if(!player_is_bomb_active(plr) && (plr->bombs > 0 || plr->iddqd) && global.frames >= plr->respawntime) {
2017-04-04 02:57:38 +02:00
player_fail_spell(plr);
// player_cancel_powersurge(plr);
2019-03-26 16:58:38 +01:00
// stage_clear_hazards(CLEAR_HAZARDS_ALL);
plr->mode->procs.bomb(plr);
plr->bombs--;
if(plr->deathtime >= global.frames) {
// death bomb - unkill the player!
plr->deathtime = -1;
if(plr->bombs) {
plr->bombs--;
}
}
if(plr->bombs < 0) {
plr->bombs = 0;
}
plr->bombtotaltime = bomb_time;
plr->recovery = global.frames + plr->bombtotaltime;
plr->bombcanceltime = 0;
plr->bombcanceldelay = 0;
assert(player_is_alive(plr));
collect_all_items(1);
return true;
}
return false;
}
static bool player_powersurge(Player *plr) {
if(
!player_is_alive(plr) ||
player_is_bomb_active(plr) ||
player_is_powersurge_active(plr) ||
plr->power + plr->power_overflow < PLR_POWERSURGE_POWERCOST
) {
return false;
}
plr->powersurge.positive = 1.0;
plr->powersurge.negative = 0.0;
plr->powersurge.time.activated = global.frames;
plr->powersurge.power = 0;
plr->powersurge.damage_accum = 0;
player_add_power(plr, -PLR_POWERSURGE_POWERCOST);
collect_all_items(1);
stagetext_add("Power Surge!", plr->pos - 64 * I, ALIGN_CENTER, get_font("standard"), RGBA(0.75, 0.75, 0.75, 0.75), 0, 45, 10, 20);
return true;
}
bool player_is_powersurge_active(Player *plr) {
return plr->powersurge.positive > plr->powersurge.negative;
}
bool player_is_bomb_active(Player *plr) {
return global.frames - plr->recovery < 0;
}
bool player_is_vulnerable(Player *plr) {
return global.frames - abs(plr->recovery) >= 0 && !plr->iddqd && player_is_alive(plr);
}
bool player_is_alive(Player *plr) {
return plr->deathtime < global.frames && global.frames >= plr->respawntime;
}
void player_cancel_bomb(Player *plr, int delay) {
if(!player_is_bomb_active(plr)) {
return;
}
if(plr->bombcanceltime) {
int canceltime_queued = plr->bombcanceltime + plr->bombcanceldelay;
int canceltime_requested = global.frames + delay;
if(canceltime_queued > canceltime_requested) {
plr->bombcanceldelay -= (canceltime_queued - canceltime_requested);
}
} else {
plr->bombcanceltime = global.frames;
plr->bombcanceldelay = delay;
}
}
static void player_powersurge_expired(Player *plr) {
plr->powersurge.time.expired = global.frames;
PowerSurgeBonus bonus;
player_powersurge_calc_bonus(plr, &bonus);
Sprite *blast = get_sprite("part/blast_huge_halo");
float scale = 2 * bonus.discharge_range / blast->w;
PARTICLE(
.sprite_ptr = blast,
.pos = plr->pos,
.color = RGBA(0.6, 1.0, 4.4, 0.0),
.draw_rule = ScaleFade,
.timeout = 20,
.args = { 0, 0, scale * (2 + 0 * I) },
.angle = M_PI*2*frand(),
);
player_add_points(&global.plr, bonus.score);
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);
log_debug(
"Power Surge expired at %i (duration: %i); baseline = %u; score = %u; discharge = %g, dmg = %g, range = %g",
plr->powersurge.time.expired,
plr->powersurge.time.expired - plr->powersurge.time.activated,
bonus.baseline,
bonus.score,
bonus.discharge_power,
bonus.discharge_damage,
bonus.discharge_range
);
plr->powersurge.damage_done = 0;
}
void player_cancel_powersurge(Player *plr) {
if(player_is_powersurge_active(plr)) {
plr->powersurge.positive = plr->powersurge.negative;
player_powersurge_expired(plr);
}
}
void player_extend_powersurge(Player *plr, float pos, float neg) {
if(player_is_powersurge_active(plr)) {
plr->powersurge.positive = clamp(plr->powersurge.positive + pos, 0, 1);
plr->powersurge.negative = clamp(plr->powersurge.negative + neg, 0, 1);
if(plr->powersurge.positive <= plr->powersurge.negative) {
player_powersurge_expired(plr);
}
}
}
2017-11-26 14:06:35 +01:00
double player_get_bomb_progress(Player *plr, double *out_speed) {
if(!player_is_bomb_active(plr)) {
if(out_speed != NULL) {
*out_speed = 1.0;
}
2017-11-26 14:06:35 +01:00
return 1;
}
int start_time = plr->recovery - plr->bombtotaltime;
int end_time = plr->recovery;
if(!plr->bombcanceltime || plr->bombcanceltime + plr->bombcanceldelay >= end_time) {
if(out_speed != NULL) {
*out_speed = 1.0;
}
return (plr->bombtotaltime - (end_time - global.frames))/(double)plr->bombtotaltime;
}
int cancel_time = plr->bombcanceltime + plr->bombcanceldelay;
int passed_time = plr->bombcanceltime - start_time;
int shortened_total_time = (plr->bombtotaltime - passed_time) - (end_time - cancel_time);
int shortened_passed_time = (global.frames - plr->bombcanceltime);
double passed_fraction = passed_time / (double)plr->bombtotaltime;
double shortened_fraction = shortened_passed_time / (double)shortened_total_time;
shortened_fraction *= (1 - passed_fraction);
if(out_speed != NULL) {
*out_speed = (plr->bombtotaltime - passed_time) / (double)shortened_total_time;
}
2017-11-26 14:06:35 +01:00
return passed_fraction + shortened_fraction;
}
2012-07-20 16:11:24 +02:00
void player_realdeath(Player *plr) {
plr->respawntime = global.frames + PLR_RESPAWN_TIME;
plr->inputflags &= ~INFLAGS_MOVE;
plr->deathpos = plr->pos;
plr->pos = VIEWPORT_W/2 + VIEWPORT_H*I+30.0*I;
plr->recovery = -(plr->respawntime + 150);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
2017-04-04 02:57:38 +02:00
player_fail_spell(plr);
if(global.stage->type != STAGE_SPELL && global.boss && global.boss->current && global.boss->current->type == AT_ExtraSpell) {
// deaths in extra spells "don't count"
return;
}
int total_power = plr->power + plr->power_overflow;
int drop = max(2, (total_power * 0.15) / POWER_VALUE);
spawn_items(plr->deathpos, ITEM_POWER, drop);
player_set_power(plr, total_power * 0.7);
plr->bombs = PLR_START_BOMBS;
plr->bomb_fragments = 0;
plr->voltage *= 0.9;
if(plr->lives-- == 0 && global.replaymode != REPLAY_PLAY) {
stage_gameover();
}
}
2018-05-19 01:24:49 +02:00
static void player_death_effect_draw_overlay(Projectile *p, int t) {
FBPair *framebuffers = stage_get_fbpair(FBPAIR_FG);
r_framebuffer(framebuffers->front);
OpenGL ES 3.0 rendering backend (#148) * First steps towards shader transpilation Needs to be manually enabled via -Dshader_transpiler=true. Requires shaderc. https://github.com/google/shaderc Not yet functional due to missing SPIRV-Cross integration. SPIRV-Cross currently does not have an official C API, and crossc is too minimal to be useful. The current plan is to extend crossc and vendor it, while also sending PRs upstream. * Integrate crossc; shader transpilation for GLES now works * fix leak * gles30 backend now playable on Mesa with 3.2 context Some rendering issues are present. Identified so far: - Marisa's lasers are invisible - Death effect looks wrong Also, a small pixmap manipulation library has been written, and the texture uploading API redesigned around it. * fix marisa lasers in GLES (uniform name clashed with builtin) * fix player death effect in GLES (another name clash) * Dump ANGLE's translated shader code in debug log * fix screenshots * Drop support for triangle fans, switch to strips Fans offer no advantage over strips, and they've been removed in D3D10+, so ANGLE has to emulate them. * crude workaround for an ANGLE bug * Re-enable GL debug labels, fix an issue with them that affected ANGLE (but was always technically a bug) * fix race condition in shaderc initialization * New SDL_RWops interface for vertex buffers * Optimize VBO streaming via buffering updates Measurable performance improvement even with the main gl33 renderer, drastic improvement with ANGLE. * Fix the depth texture binding problem under ANGLE Apparently it hates GL_DEPTH_COMPONENT16 for some reason. Sized internal formats are not supported in GLES 2.0 anyway, so not using them is probably a good idea. * fix GLES2.0 segfault (the backend still doesn't work, though) * dump GL extensions at info log level, not debug * get around a Mesa bug; more correct texture format table for GLES2 * Correct GLES3 texture format table according to the spec Not a Mesa bug after all * require crossc>=1.5.0, fallback to subproject * Request at least 8bit per color channel in GL backends * Forbid lto for static windows builds with shader_transpiler=true * fix edge case segfault * Add basic ANGLE bundling support to the build system Windows only, and no NSIS support yet * Fix various windows-related build system and installer brokenness * Disable gles backends by default * update documentation
2018-10-02 00:36:10 +02:00
r_uniform_sampler("noise_tex", "static");
2018-05-18 20:15:11 +02:00
r_uniform_int("frames", global.frames);
r_uniform_float("progress", t / p->timeout);
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
r_uniform_vec2("clear_origin", creal(global.plr.pos), VIEWPORT_H - cimag(global.plr.pos));
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
fbpair_swap(framebuffers);
2018-05-19 01:24:49 +02:00
// This change must propagate, hence the r_state salsa. Yes, pop then push, I know what I'm doing.
r_state_pop();
r_framebuffer(framebuffers->back);
2018-05-19 01:24:49 +02:00
r_state_push();
}
static void player_death_effect_draw_sprite(Projectile *p, int t) {
float s = t / p->timeout;
float stretch_range = 3, sx, sy;
sx = 0.5 + 0.5 * cos(M_PI * (2 * pow(s, 0.5) + 1));
sx = (1 - s) * (1 + (stretch_range - 1) * sx) + s * stretch_range * sx;
sy = 1 + pow(s, 3);
if(sx <= 0 || sy <= 0) {
return;
}
r_draw_sprite(&(SpriteParams) {
.sprite_ptr = p->sprite,
.pos = { creal(p->pos), cimag(p->pos) },
.scale = { .x = sx, .y = sy },
});
}
static int player_death_effect(Projectile *p, int t) {
if(t < 0) {
if(t == EVENT_DEATH) {
for(int i = 0; i < 12; ++i) {
PARTICLE(
.sprite = "blast",
.pos = p->pos + 2 * frand() * cexp(I*M_PI*2*frand()),
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
.color = RGBA(0.15, 0.2, 0.5, 0),
2018-05-19 01:24:49 +02:00
.timeout = 12 + i + 2 * nfrand(),
.draw_rule = GrowFade,
.args = { 0, 20 + i },
.angle = M_PI*2*frand(),
.flags = PFLAG_NOREFLECT,
.layer = LAYER_OVERLAY,
);
}
}
return ACTION_ACK;
}
return ACTION_NONE;
2018-05-18 20:15:11 +02:00
}
2012-07-20 16:11:24 +02:00
void player_death(Player *plr) {
if(!player_is_vulnerable(plr) || stage_is_cleared()) {
2018-01-02 08:36:14 +01:00
return;
}
2018-01-02 08:36:14 +01:00
play_sound("death");
for(int i = 0; i < 60; i++) {
tsrand_fill(2);
PARTICLE(
.sprite = "flare",
.pos = plr->pos,
.rule = linear,
.timeout = 40,
.draw_rule = Shrink,
.args = { (3+afrand(0)*7)*cexp(I*tsrand_a(1)) },
.flags = PFLAG_NOREFLECT,
2018-05-18 20:15:11 +02:00
);
}
2018-05-18 20:15:11 +02:00
stage_clear_hazards(CLEAR_HAZARDS_ALL);
2018-05-19 01:24:49 +02:00
PARTICLE(
.sprite = "blast",
.pos = plr->pos,
.color = RGBA(0.5, 0.15, 0.15, 0),
.timeout = 35,
.draw_rule = GrowFade,
.args = { 0, 2.4 },
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
);
PARTICLE(
.pos = plr->pos,
.size = 1+I,
.timeout = 90,
.draw_rule = player_death_effect_draw_overlay,
.blend = BLEND_NONE,
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
.layer = LAYER_OVERLAY,
.shader = "player_death",
);
PARTICLE(
.sprite_ptr = aniplayer_get_frame(&plr->ani),
.pos = plr->pos,
.timeout = 30,
.rule = player_death_effect,
.draw_rule = player_death_effect_draw_sprite,
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
.layer = LAYER_PLAYER_FOCUS, // LAYER_OVERLAY | 1,
);
plr->deathtime = global.frames + floor(player_property(plr, PLR_PROP_DEATHBOMB_WINDOW));
if(player_is_powersurge_active(plr)) {
player_cancel_powersurge(plr);
// player_bomb(plr);
}
}
2018-07-30 09:04:09 +02:00
static DamageResult ent_damage_player(EntityInterface *ent, const DamageInfo *dmg) {
Player *plr = ENT_CAST(ent, Player);
if(
!player_is_vulnerable(plr) ||
2018-07-30 09:04:09 +02:00
(dmg->type != DMG_ENEMY_SHOT && dmg->type != DMG_ENEMY_COLLISION)
) {
return DMG_RESULT_IMMUNE;
}
player_death(plr);
return DMG_RESULT_OK;
}
void player_damage_hook(Player *plr, EntityInterface *target, DamageInfo *dmg) {
if(player_is_powersurge_active(plr) && dmg->type == DMG_PLAYER_SHOT) {
dmg->amount *= 1.2;
}
}
static PlrInputFlag key_to_inflag(KeyIndex key) {
switch(key) {
case KEY_UP: return INFLAG_UP;
case KEY_DOWN: return INFLAG_DOWN;
case KEY_LEFT: return INFLAG_LEFT;
case KEY_RIGHT: return INFLAG_RIGHT;
case KEY_FOCUS: return INFLAG_FOCUS;
case KEY_SHOT: return INFLAG_SHOT;
case KEY_SKIP: return INFLAG_SKIP;
default: return 0;
}
}
static bool player_updateinputflags(Player *plr, PlrInputFlag flags) {
2017-10-01 02:48:55 +02:00
if(flags == plr->inputflags) {
return false;
}
if((flags & INFLAG_FOCUS) && !(plr->inputflags & INFLAG_FOCUS)) {
plr->focus_circle.first->birthtime = global.frames;
}
plr->inputflags = flags;
return true;
}
static bool player_updateinputflags_moveonly(Player *plr, PlrInputFlag flags) {
return player_updateinputflags(plr, (flags & INFLAGS_MOVE) | (plr->inputflags & ~INFLAGS_MOVE));
}
static bool player_setinputflag(Player *plr, KeyIndex key, bool mode) {
PlrInputFlag newflags = plr->inputflags;
PlrInputFlag keyflag = key_to_inflag(key);
if(!keyflag) {
return false;
}
if(mode) {
newflags |= keyflag;
2012-08-12 18:00:56 +02:00
} else {
newflags &= ~keyflag;
2012-08-12 18:00:56 +02:00
}
return player_updateinputflags(plr, newflags);
}
static bool player_set_axis(int *aptr, uint16_t value) {
int16_t new = (int16_t)value;
if(*aptr == new) {
return false;
}
*aptr = new;
return true;
}
2017-10-31 10:48:30 +01:00
void player_event(Player *plr, uint8_t type, uint16_t value, bool *out_useful, bool *out_cheat) {
bool useful = true;
bool cheat = false;
2017-10-31 10:48:30 +01:00
bool is_replay = global.replaymode == REPLAY_PLAY;
switch(type) {
case EV_PRESS:
if(global.dialog && (value == KEY_SHOT || value == KEY_BOMB)) {
2017-11-12 18:16:15 +01:00
useful = page_dialog(&global.dialog);
break;
}
switch(value) {
case KEY_BOMB:
useful = player_bomb(plr);
if(!useful && plr->iddqd) {
// smooth bomb cancellation test
player_cancel_bomb(plr, 60);
useful = true;
}
break;
case KEY_SPECIAL:
if(global.dialog) {
useful = false;
break;
}
useful = player_powersurge(plr);
if(!useful/* && plr->iddqd*/) {
player_cancel_powersurge(plr);
useful = true;
}
break;
case KEY_IDDQD:
plr->iddqd = !plr->iddqd;
cheat = true;
break;
2017-03-06 13:02:46 +01:00
case KEY_POWERUP:
useful = player_add_power(plr, 100);
cheat = true;
2017-03-06 13:02:46 +01:00
break;
case KEY_POWERDOWN:
useful = player_add_power(plr, -100);
cheat = true;
2017-03-06 13:02:46 +01:00
break;
default:
useful = player_setinputflag(plr, value, true);
break;
}
break;
case EV_RELEASE:
useful = player_setinputflag(plr, value, false);
break;
2012-08-15 16:36:39 +02:00
case EV_AXIS_LR:
useful = player_set_axis(&plr->axis_lr, value);
2012-08-15 16:36:39 +02:00
break;
2012-08-15 16:36:39 +02:00
case EV_AXIS_UD:
useful = player_set_axis(&plr->axis_ud, value);
break;
case EV_INFLAGS:
useful = player_updateinputflags(plr, value);
2012-08-15 16:36:39 +02:00
break;
case EV_CONTINUE:
// continuing in the same frame will desync the replay,
// so schedule it for the next one
plr->continuetime = global.frames + 1;
useful = true;
break;
default:
log_warn("Can not handle event: [%i:%02x:%04x]", global.frames, type, value);
useful = false;
break;
}
2017-10-31 10:48:30 +01:00
if(is_replay) {
if(!useful) {
log_warn("Useless event in replay: [%i:%02x:%04x]", global.frames, type, value);
}
if(cheat) {
log_warn("Cheat event in replay: [%i:%02x:%04x]", global.frames, type, value);
if( !(global.replay.flags & REPLAY_GFLAG_CHEATS) ||
!(global.replay_stage->flags & REPLAY_SFLAG_CHEATS)) {
log_warn("...but this replay was NOT properly cheat-flagged! Not cool, not cool at all");
}
}
if(type == EV_CONTINUE && (
!(global.replay.flags & REPLAY_GFLAG_CONTINUES) ||
!(global.replay_stage->flags & REPLAY_SFLAG_CONTINUES))) {
log_warn("Continue event in replay: [%i:%02x:%04x], but this replay was not properly continue-flagged", global.frames, type, value);
}
}
if(out_useful) {
*out_useful = useful;
}
if(out_cheat) {
*out_cheat = cheat;
}
}
bool player_event_with_replay(Player *plr, uint8_t type, uint16_t value) {
bool useful, cheat;
assert(global.replaymode == REPLAY_RECORD);
2017-10-31 10:48:30 +01:00
if(config_get_int(CONFIG_SHOT_INVERTED) && value == KEY_SHOT && (type == EV_PRESS || type == EV_RELEASE)) {
type = type == EV_PRESS ? EV_RELEASE : EV_PRESS;
}
player_event(plr, type, value, &useful, &cheat);
if(useful) {
replay_stage_event(global.replay_stage, global.frames, type, value);
if(type == EV_CONTINUE) {
global.replay.flags |= REPLAY_GFLAG_CONTINUES;
global.replay_stage->flags |= REPLAY_SFLAG_CONTINUES;
}
if(cheat) {
global.replay.flags |= REPLAY_GFLAG_CHEATS;
global.replay_stage->flags |= REPLAY_SFLAG_CHEATS;
}
return true;
} else {
log_debug("Useless event discarded: [%i:%02x:%04x]", global.frames, type, value);
}
return false;
}
2012-08-15 16:36:39 +02:00
// free-axis movement
static bool player_applymovement_gamepad(Player *plr) {
if(!plr->axis_lr && !plr->axis_ud) {
if(plr->gamepadmove) {
plr->gamepadmove = false;
plr->inputflags &= ~INFLAGS_MOVE;
}
return false;
}
complex direction = (
gamepad_normalize_axis_value(plr->axis_lr) +
gamepad_normalize_axis_value(plr->axis_ud) * I
);
if(cabs(direction) > 1) {
direction /= cabs(direction);
}
2017-03-06 16:32:51 +01:00
int sr = sign(creal(direction));
int si = sign(cimag(direction));
player_updateinputflags_moveonly(plr,
(INFLAG_UP * (si == -1)) |
(INFLAG_DOWN * (si == 1)) |
(INFLAG_LEFT * (sr == -1)) |
(INFLAG_RIGHT * (sr == 1))
);
if(direction) {
plr->gamepadmove = true;
2012-08-15 16:36:39 +02:00
player_move(&global.plr, direction);
}
return true;
2012-08-15 16:36:39 +02:00
}
2018-05-05 11:23:56 +02:00
static const char *moveseqname(int dir) {
switch(dir) {
2018-05-05 11:23:56 +02:00
case -1: return "left";
case 0: return "main";
case 1: return "right";
default: log_fatal("Invalid player animation dir given");
}
2018-05-05 11:23:56 +02:00
}
2018-05-05 11:23:56 +02:00
static void player_ani_moving(Player *plr, int dir) {
if(plr->lastmovesequence == dir)
return;
2018-05-05 11:23:56 +02:00
const char *seqname = moveseqname(dir);
const char *lastseqname = moveseqname(plr->lastmovesequence);
char *transition = strjoin(lastseqname,"2",seqname,NULL);
aniplayer_hard_switch(&plr->ani,transition,1);
aniplayer_queue(&plr->ani,seqname,0);
plr->lastmovesequence = dir;
2018-05-05 11:23:56 +02:00
free(transition);
2017-10-03 17:25:38 +02:00
}
void player_applymovement(Player *plr) {
plr->velocity = 0;
if(!player_is_alive(plr))
return;
bool gamepad = player_applymovement_gamepad(plr);
int up = plr->inputflags & INFLAG_UP;
int down = plr->inputflags & INFLAG_DOWN;
int left = plr->inputflags & INFLAG_LEFT;
int right = plr->inputflags & INFLAG_RIGHT;
if(left && !right) {
player_ani_moving(plr,-1);
} else if(right && !left) {
player_ani_moving(plr,1);
} else {
player_ani_moving(plr,0);
2012-08-15 16:36:39 +02:00
}
if(gamepad) {
2012-08-15 16:36:39 +02:00
return;
}
complex direction = 0;
if(up) direction -= 1.0*I;
if(down) direction += 1.0*I;
2018-05-18 20:15:11 +02:00
if(left) direction -= 1.0;
if(right) direction += 1.0;
2012-07-20 16:11:24 +02:00
if(cabs(direction))
direction /= cabs(direction);
if(direction)
2012-07-20 16:11:24 +02:00
player_move(&global.plr, direction);
}
void player_fix_input(Player *plr) {
// correct input state to account for any events we might have missed,
// usually because the pause menu ate them up
PlrInputFlag newflags = plr->inputflags;
2017-10-31 10:48:30 +01:00
bool invert_shot = config_get_int(CONFIG_SHOT_INVERTED);
for(KeyIndex key = KEYIDX_FIRST; key <= KEYIDX_LAST; ++key) {
int flag = key_to_inflag(key);
if(flag && !(plr->gamepadmove && (flag & INFLAGS_MOVE))) {
bool flagset = plr->inputflags & flag;
bool keyheld = gamekeypressed(key);
2017-10-31 10:48:30 +01:00
if(invert_shot && key == KEY_SHOT) {
keyheld = !keyheld;
}
if(flagset && !keyheld) {
newflags &= ~flag;
} else if(!flagset && keyheld) {
newflags |= flag;
}
}
}
if(newflags != plr->inputflags) {
player_event_with_replay(plr, EV_INFLAGS, newflags);
}
int axis_lr = gamepad_player_axis_value(PLRAXIS_LR);
int axis_ud = gamepad_player_axis_value(PLRAXIS_UD);
if(plr->axis_lr != axis_lr) {
player_event_with_replay(plr, EV_AXIS_LR, axis_lr);
}
if(plr->axis_ud != axis_ud) {
player_event_with_replay(plr, EV_AXIS_UD, axis_ud);
}
}
2012-08-14 16:14:53 +02:00
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
void player_graze(Player *plr, complex pos, int pts, int effect_intensity, const Color *color) {
if(++plr->graze >= PLR_MAX_GRAZE) {
log_debug("Graze counter overflow");
plr->graze = PLR_MAX_GRAZE;
2018-01-09 19:49:30 +01:00
}
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
pos = (pos + plr->pos) * 0.5;
player_add_points(plr, pts);
2012-08-14 16:14:53 +02:00
play_sound("graze");
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
Color *c = COLOR_COPY(color);
color_add(c, RGBA(1, 1, 1, 1));
color_mul_scalar(c, 0.5);
c->a = 0;
for(int i = 0; i < effect_intensity; ++i) {
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
tsrand_fill(4);
PARTICLE(
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
.sprite = "graze",
.color = c,
.pos = pos,
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
.rule = asymptotic,
.timeout = 24 + 5 * afrand(2),
.draw_rule = ScaleSquaredFade,
.args = { 0.2 * (1+afrand(0)*5)*cexp(I*M_PI*2*afrand(1)), 16 * (1 + 0.5 * anfrand(3)), 1 },
.flags = PFLAG_NOREFLECT,
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
// .layer = LAYER_PARTICLE_LOW,
);
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
color_mul_scalar(c, 0.4);
2012-08-14 16:14:53 +02:00
}
spawn_items(pos, ITEM_POWER_MINI, 1);
2012-08-14 16:14:53 +02:00
}
static void player_add_fragments(Player *plr, int frags, int *pwhole, int *pfrags, int maxfrags, int maxwhole, const char *fragsnd, const char *upsnd, int score_per_excess) {
int total_frags = *pfrags + maxfrags * *pwhole;
int excess_frags = total_frags + frags - maxwhole * maxfrags;
if(excess_frags > 0) {
player_add_points(plr, excess_frags * score_per_excess);
frags -= excess_frags;
}
*pfrags += frags;
int up = *pfrags / maxfrags;
*pwhole += up;
*pfrags %= maxfrags;
if(up) {
play_sound(upsnd);
}
if(frags) {
// FIXME: when we have the extra life/bomb sounds,
// don't play this if upsnd was just played.
play_sound(fragsnd);
}
if(*pwhole >= maxwhole) {
*pwhole = maxwhole;
*pfrags = 0;
}
}
void player_add_life_fragments(Player *plr, int frags) {
player_add_fragments(
plr,
frags,
&plr->lives,
&plr->life_fragments,
PLR_MAX_LIFE_FRAGMENTS,
PLR_MAX_LIVES,
"item_generic", // FIXME: replacement needed
"extra_life",
(plr->point_item_value * 10) / PLR_MAX_LIFE_FRAGMENTS
);
}
void player_add_bomb_fragments(Player *plr, int frags) {
player_add_fragments(
plr,
frags,
&plr->bombs,
&plr->bomb_fragments,
PLR_MAX_BOMB_FRAGMENTS,
PLR_MAX_BOMBS,
"item_generic", // FIXME: replacement needed
"extra_bomb",
(plr->point_item_value * 5) / PLR_MAX_BOMB_FRAGMENTS
);
}
void player_add_lives(Player *plr, int lives) {
player_add_life_fragments(plr, PLR_MAX_LIFE_FRAGMENTS);
}
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) {
plr->points += points;
while(plr->points >= plr->extralife_threshold) {
plr->extralife_threshold = player_next_extralife_threshold(++plr->extralives_given);
2019-02-28 11:10:03 +01:00
player_add_lives(plr, 1);
}
}
void player_add_piv(Player *plr, uint piv) {
uint v = plr->point_item_value + piv;
if(v > PLR_MAX_PIV || v < plr->point_item_value) {
plr->point_item_value = PLR_MAX_PIV;
} else {
plr->point_item_value = v;
}
}
void player_add_voltage(Player *plr, uint voltage) {
uint v = plr->voltage + voltage;
if(v > PLR_MAX_VOLTAGE || v < plr->voltage) {
plr->voltage = PLR_MAX_VOLTAGE;
} else {
plr->voltage = v;
}
player_add_bomb_fragments(plr, voltage);
}
bool player_drain_voltage(Player *plr, uint voltage) {
// TODO: animate (or maybe handle that at stagedraw level)
if(plr->voltage >= voltage) {
plr->voltage -= voltage;
return true;
}
plr->voltage = 0;
return false;
}
2018-07-30 09:04:09 +02:00
void player_register_damage(Player *plr, EntityInterface *target, const DamageInfo *damage) {
if(!DAMAGETYPE_IS_PLAYER(damage->type)) {
2018-07-30 09:04:09 +02:00
return;
}
complex pos = NAN;
2018-07-30 09:04:09 +02:00
if(target != NULL) {
switch(target->type) {
case ENT_ENEMY: {
player_add_points(&global.plr, damage->amount * 0.5);
pos = ENT_CAST(target, Enemy)->pos;
2018-07-30 09:04:09 +02:00
break;
}
case ENT_BOSS: {
player_add_points(&global.plr, damage->amount * 0.2);
pos = ENT_CAST(target, Boss)->pos;
2018-07-30 09:04:09 +02:00
break;
}
default: break;
}
}
if(!isnan(creal(pos)) && damage->type == DMG_PLAYER_DISCHARGE) {
double rate = target->type == ENT_BOSS ? 110 : 256;
spawn_and_collect_items(pos, 1, ITEM_VOLTAGE, (int)(damage->amount / rate));
}
if(player_is_powersurge_active(plr)) {
plr->powersurge.damage_done += damage->amount;
plr->powersurge.damage_accum += damage->amount;
if(!isnan(creal(pos))) {
double rate = 500;
while(plr->powersurge.damage_accum > rate) {
plr->powersurge.damage_accum -= rate;
spawn_item(pos, ITEM_SURGE);
}
}
}
2018-07-30 09:04:09 +02:00
#ifdef PLR_DPS_STATS
while(global.frames > plr->dmglogframe) {
memmove(plr->dmglog + 1, plr->dmglog, sizeof(plr->dmglog) - sizeof(*plr->dmglog));
plr->dmglog[0] = 0;
plr->dmglogframe++;
}
2018-07-30 09:04:09 +02:00
plr->dmglog[0] += damage->amount;
#endif
}
uint64_t player_next_extralife_threshold(uint64_t step) {
static uint64_t base = 5000000;
return base * (step * step + step + 2) / 2;
}
void player_preload(void) {
const int flags = RESF_DEFAULT;
2018-05-18 20:15:11 +02:00
preload_resources(RES_SHADER_PROGRAM, flags,
"player_death",
NULL);
preload_resources(RES_TEXTURE, flags,
"static",
NULL);
preload_resources(RES_SPRITE, flags,
"fairy_circle",
"focus",
"part/blast_huge_halo",
"part/powersurge_field",
NULL);
preload_resources(RES_SFX, flags | RESF_OPTIONAL,
"death",
"extra_bomb",
"extra_life",
"full_power",
"generic_shot",
"graze",
2018-08-14 02:56:16 +02:00
"hit0",
"hit1",
"powerup",
NULL);
}
Add Reimu Hakurei as a playable character (#106) * Reimu (#101) * add the reimu * Add Reimu story * account for various blunders * add reimu dialog picture * Reimu: WIP yin-yang orbs * reimu: fix up indents * Reimu: swap the shotmode names to match the kanji order in her Japanese name * Reimu: compatibility with the latest system * WIP ReimuA crap * ReimuA homing trails * more ReimuA stuff * more ReimuA adjustments + enhanced DPS stats * Reimu: stubs for new player animation sequences * Reimu: occupy the 0th character slot * Reimu: tweak needle sprite * Reimu: buff movement speed to better match Touhou * Reimu: fixup for the recent projectile changes * ReimuA: make homing shots a bit smaller; give them custom effect on collision * Reimu: add intermediate frames; move some loose sprites to the atlas * Reimu: fix compile errors * replace DBL_MAX by INFINITY * Don’t draw reimu orbs twice fixes #127 * add new reimu dialog pic * ReimuA adjustments (mostly homing); it's still OP * wip ReimuB gaps * still not sure where i'm going with these gaps * meh * Reimu: premultiplied alpha fixups after rebase * reimuB shot pattern with basic power scaling (not balanced at all) * reimuB: some lame-ass particle effects * ReimuB bomb effect prototype * reimuA bomb prototype * fix reimu shots for the new damage system * Reimu: use the new player_is_bomb_active() function, add placeholder BG for ReimuB * some reimuB bomb projectiles * ReimuB bomb bg and some framebuffer utils required to support it. Might reuse this at least in part for ReimuA unless we come up with something better. * hack to fix ReimuB bomb fade; refactoring needed * reimuA damaging bombs * fix ub * prevent nan when reimuA bombs without enemies present * add a bomb_bg to reimuA * ... * various fantasy seal tweaks * Reimu: placeholder bomb sounds; slight fantasy seal buff * fix null pointer dereference * Reimu "balance" adjustments; minor fixes * putting bandaids over gunshot wounds * Add aoe damage and bullet cancel to ReimuB's bomb * more exorcism porn * make reimu bomb bg runes better visible on dark backgrounds * More ReimuA shot changes
2018-08-11 21:13:48 +02:00
// FIXME: where should this be?
complex plrutil_homing_target(complex org, complex fallback) {
double mindst = INFINITY;
complex target = fallback;
if(global.boss && boss_is_vulnerable(global.boss)) {
target = global.boss->pos;
mindst = cabs(target - org);
}
for(Enemy *e = global.enemies.first; e; e = e->next) {
if(e->hp == ENEMY_IMMUNE) {
continue;
}
double dst = cabs(e->pos - org);
if(dst < mindst) {
mindst = dst;
target = e->pos;
}
}
return target;
}