WIP fucking badass Marisa lasers
This commit is contained in:
parent
5a9c4b3080
commit
62c34e3b5a
20 changed files with 373 additions and 95 deletions
BIN
resources/gfx/part/magic_star.png
Normal file
BIN
resources/gfx/part/magic_star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
resources/gfx/part/marisa_laser0.png
Normal file
BIN
resources/gfx/part/marisa_laser0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
BIN
resources/gfx/part/marisa_laser1.png
Normal file
BIN
resources/gfx/part/marisa_laser1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
37
resources/shader/marisa_laser.sha
Normal file
37
resources/shader/marisa_laser.sha
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
#version 110
|
||||
|
||||
varying vec4 TexCoord0;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = ftransform();
|
||||
gl_FrontColor = gl_Color;
|
||||
|
||||
TexCoord0 = gl_MultiTexCoord0;
|
||||
}
|
||||
|
||||
%% -- FRAG
|
||||
#version 110
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 color;
|
||||
uniform float alphamod;
|
||||
uniform float length;
|
||||
// uniform float cutoff;
|
||||
|
||||
varying vec4 TexCoord0;
|
||||
|
||||
void main(void) {
|
||||
vec4 uv = TexCoord0;
|
||||
vec2 uv_transformed = (uv * gl_TextureMatrixTranspose[0]).xy;
|
||||
vec2 uv_scaled = (uv * gl_TextureMatrix[0]).xy;
|
||||
|
||||
float edgefactor = 20.0 * pow(alphamod, 2.0);
|
||||
float edgemod = min(1.0, uv_scaled.x * edgefactor) * clamp((length - uv_scaled.x) * edgefactor, 0.0, 1.0);
|
||||
// edgemod = pow(edgemod, 1.0 + abs(uv_scaled.y - 0.5) * 2.0);
|
||||
float a = alphamod * edgemod;
|
||||
|
||||
gl_FragColor = texture2D(tex, uv_transformed);
|
||||
// gl_FragColor *= float(uv.x <= (1.0 - cutoff));
|
||||
gl_FragColor *= vec4(color.rgb, color.a * a);
|
||||
}
|
10
src/fbo.c
10
src/fbo.c
|
@ -14,7 +14,7 @@ static float sanitize_scale(float scale) {
|
|||
return max(0.1, scale);
|
||||
}
|
||||
|
||||
void init_fbo(FBO *fbo, float scale) {
|
||||
void init_fbo(FBO *fbo, float scale, int type) {
|
||||
glGenTextures(1, &fbo->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->tex);
|
||||
|
||||
|
@ -29,7 +29,7 @@ void init_fbo(FBO *fbo, float scale) {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbo->nw, fbo->nh, 0, GL_BGR, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, type, fbo->nw, fbo->nh, 0, type, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
glGenFramebuffers(1,&fbo->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fbo);
|
||||
|
@ -50,16 +50,16 @@ void init_fbo(FBO *fbo, float scale) {
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void reinit_fbo(FBO *fbo, float scale) {
|
||||
void reinit_fbo(FBO *fbo, float scale, int type) {
|
||||
if(!fbo->scale) {
|
||||
// fbo was never initialized
|
||||
init_fbo(fbo, scale);
|
||||
init_fbo(fbo, scale, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if(fbo->scale != sanitize_scale(scale)) {
|
||||
delete_fbo(fbo);
|
||||
init_fbo(fbo, scale);
|
||||
init_fbo(fbo, scale, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ typedef struct {
|
|||
float scale;
|
||||
} FBO;
|
||||
|
||||
void init_fbo(FBO *fbo, float scale);
|
||||
void reinit_fbo(FBO *fbo, float scale);
|
||||
void init_fbo(FBO *fbo, float scale, int type);
|
||||
void reinit_fbo(FBO *fbo, float scale, int type);
|
||||
void draw_fbo(FBO *fbo);
|
||||
void draw_fbo_viewport(FBO *fbo);
|
||||
void delete_fbo(FBO *fbo);
|
||||
|
|
|
@ -110,7 +110,7 @@ void process_items(void) {
|
|||
if(v == 1) {
|
||||
switch(item->type) {
|
||||
case Power:
|
||||
player_set_power(&global.plr, global.plr.power + POWER_VALUE,true);
|
||||
player_set_power(&global.plr, global.plr.power + POWER_VALUE);
|
||||
play_sound("item_generic");
|
||||
break;
|
||||
case Point:
|
||||
|
|
25
src/player.c
25
src/player.c
|
@ -35,18 +35,19 @@ void player_stage_pre_init(Player *plr) {
|
|||
}
|
||||
|
||||
void player_stage_post_init(Player *plr) {
|
||||
// TODO: remove handle_fullpower from player_set_power and get rid of this hack
|
||||
short power = global.plr.power;
|
||||
global.plr.power = -1;
|
||||
delete_enemies(&global.plr.slaves);
|
||||
player_set_power(&global.plr, power, false);
|
||||
|
||||
assert(plr->mode != NULL);
|
||||
aniplayer_create(&plr->ani, get_ani(plr->mode->character->player_sprite_name));
|
||||
|
||||
// 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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void player_full_power(Player *plr) {
|
||||
|
@ -55,7 +56,7 @@ static void player_full_power(Player *plr) {
|
|||
stagetext_add("Full Power!", VIEWPORT_W * 0.5 + VIEWPORT_H * 0.33 * I, AL_Center, _fonts.mainmenu, rgb(1, 1, 1), 0, 60, 20, 20);
|
||||
}
|
||||
|
||||
bool player_set_power(Player *plr, short npow, bool handle_fullpower) {
|
||||
bool player_set_power(Player *plr, short npow) {
|
||||
npow = clamp(npow, 0, PLR_MAX_POWER);
|
||||
|
||||
if(plr->mode->procs.power) {
|
||||
|
@ -65,7 +66,7 @@ bool player_set_power(Player *plr, short npow, bool handle_fullpower) {
|
|||
int oldpow = plr->power;
|
||||
plr->power = npow;
|
||||
|
||||
if(plr->power == PLR_MAX_POWER && oldpow < PLR_MAX_POWER && handle_fullpower) {
|
||||
if(plr->power == PLR_MAX_POWER && oldpow < PLR_MAX_POWER) {
|
||||
player_full_power(plr);
|
||||
}
|
||||
|
||||
|
@ -408,7 +409,7 @@ void player_realdeath(Player *plr) {
|
|||
int drop = max(2, (plr->power * 0.15) / POWER_VALUE);
|
||||
spawn_items(plr->deathpos, Power, drop, NULL);
|
||||
|
||||
player_set_power(plr, plr->power * 0.7,true);
|
||||
player_set_power(plr, plr->power * 0.7);
|
||||
plr->bombs = PLR_START_BOMBS;
|
||||
plr->bomb_fragments = 0;
|
||||
|
||||
|
@ -513,12 +514,12 @@ void player_event(Player *plr, uint8_t type, uint16_t value, bool warn, bool *ou
|
|||
break;
|
||||
|
||||
case KEY_POWERUP:
|
||||
useful = player_set_power(plr, plr->power + 100, true);
|
||||
useful = player_set_power(plr, plr->power + 100);
|
||||
cheat = true;
|
||||
break;
|
||||
|
||||
case KEY_POWERDOWN:
|
||||
useful = player_set_power(plr, plr->power - 100, true);
|
||||
useful = player_set_power(plr, plr->power - 100);
|
||||
cheat = true;
|
||||
break;
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ void player_draw(Player*);
|
|||
void player_logic(Player*);
|
||||
bool player_should_shoot(Player *plr, bool extra);
|
||||
|
||||
bool player_set_power(Player *plr, short npow, bool handle_fullpower);
|
||||
bool player_set_power(Player *plr, short npow);
|
||||
|
||||
void player_move(Player*, complex delta);
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ typedef struct PlayerCharacter {
|
|||
} ending;
|
||||
} PlayerCharacter;
|
||||
|
||||
typedef void (*PlayerModeInitProc)(Player *plr);
|
||||
typedef void (*PlayerModeThinkProc)(Player *plr);
|
||||
typedef void (*PlayerModeShotProc)(Player *plr);
|
||||
typedef void (*PlayerModeBombProc)(Player *plr);
|
||||
|
@ -65,6 +66,7 @@ typedef struct PlayerMode {
|
|||
ShotModeID shot_mode;
|
||||
|
||||
struct {
|
||||
PlayerModeInitProc init;
|
||||
PlayerModeThinkProc think;
|
||||
PlayerModeShotProc shot;
|
||||
PlayerModeBombProc bomb;
|
||||
|
|
|
@ -37,7 +37,7 @@ void marisa_common_shot(Player *plr) {
|
|||
void marisa_common_slave_draw(Enemy *e, int t) {
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(e->pos), cimag(e->pos), -1);
|
||||
glRotatef(global.frames * 3, 0, 0, 1);
|
||||
// glRotatef(global.frames * 3, 0, 0, 1);
|
||||
draw_texture(0,0,"part/lasercurve");
|
||||
glPopMatrix();
|
||||
}
|
||||
|
|
|
@ -10,55 +10,259 @@
|
|||
#include "plrmodes.h"
|
||||
#include "marisa.h"
|
||||
|
||||
static void marisa_laser_draw(Projectile *p, int t) {
|
||||
if(REF(p->args[1]) == NULL)
|
||||
return;
|
||||
static void draw_laser_beam(complex src, complex dst, double size, double step, double t, Texture *tex, int u_length) {
|
||||
complex dir = dst - src;
|
||||
complex center = (src + dst) * 0.5;
|
||||
|
||||
if(cimag(p->pos) - cimag(global.plr.pos) < 90) {
|
||||
float s = resources.fbo.fg[0].scale;
|
||||
glScissor(0, s * (VIEWPORT_H - cimag(((Enemy *)REF(p->args[1]))->pos)), VIEWPORT_W*s, VIEWPORT_H*s);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glPushMatrix();
|
||||
|
||||
ProjDraw(p, t);
|
||||
glTranslatef(creal(center), cimag(center), 0);
|
||||
glRotatef(180/M_PI*carg(dir), 0, 0, 1);
|
||||
glScalef(cabs(dir), size, 1);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glTranslatef(-cimag(src) / step + t, 0, 0);
|
||||
glScalef(cabs(dir) / step, 1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gltex);
|
||||
glUniform1f(u_length, cabs(dir) / step);
|
||||
draw_quad();
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static int marisa_laser(Projectile *p, int t) {
|
||||
if(t == EVENT_DEATH) {
|
||||
free_ref(p->args[1]);
|
||||
return 1;
|
||||
static complex trace_laser(complex origin, complex vel, int damage) {
|
||||
complex target = origin;
|
||||
Projectile *p = NULL;
|
||||
|
||||
create_projectile_p(&p, get_tex("proj/ball"), origin, 0, NULL, linear, vel, 0, 0, 0);
|
||||
p->type = PlrProj + damage;
|
||||
|
||||
for(int t = 0; p; ++t) {
|
||||
int action = p->rule(p, t);
|
||||
int col = collision_projectile(p);
|
||||
|
||||
if(col || action == ACTION_DESTROY || !projectile_in_viewport(p)) {
|
||||
complex nudge = -10 * vel / cabs(vel);
|
||||
target = p->pos + nudge;
|
||||
|
||||
if(col) {
|
||||
tsrand_fill(3);
|
||||
create_particle2c("flare", target, 0, Shrink, timeout_linear, 3 + 5 * afrand(2), (2+afrand(0)*6)*cexp(I*M_PI*2*afrand(1)))->type=PlrProj;
|
||||
}
|
||||
|
||||
delete_projectile(&p, p);
|
||||
}
|
||||
}
|
||||
|
||||
if(REF(p->args[1]) == NULL)
|
||||
return target;
|
||||
}
|
||||
|
||||
static void set_color(int u_clr, Color c) {
|
||||
float ca[4];
|
||||
parse_color_array(c, ca);
|
||||
glUniform4fv(u_clr, 1, ca);
|
||||
}
|
||||
|
||||
static float set_alpha(int u_alpha, float a) {
|
||||
if(a) {
|
||||
glUniform1f(u_alpha, a);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static float set_alpha_dimmed(int u_alpha, float a) {
|
||||
return set_alpha(u_alpha, a * a * 0.5);
|
||||
}
|
||||
|
||||
static void draw_magic_star(complex pos, double a, Color c1, Color c2) {
|
||||
if(a <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Color mul = rgba(1, 1, 1, a);
|
||||
c1 = multiply_colors(c1, mul);
|
||||
c2 = multiply_colors(c2, mul);
|
||||
|
||||
Texture *tex = get_tex("part/magic_star");
|
||||
Shader *shader = get_shader("bullet_color");
|
||||
int u_clr = uniloc(shader, "color");
|
||||
glUseProgram(shader->prog);
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(pos), cimag(pos), -1);
|
||||
glScalef(0.25, 0.25, 1);
|
||||
glPushMatrix();
|
||||
set_color(u_clr, c1);
|
||||
glRotatef(global.frames * 3, 0, 0, 1);
|
||||
draw_texture_p(0, 0, tex);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
set_color(u_clr, c2);
|
||||
glRotatef(global.frames * -3, 0, 0, 1);
|
||||
draw_texture_p(0, 0, tex);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
static void marisa_laser_slave_draw(Enemy *e, int t) {
|
||||
float laser_alpha = global.plr.slaves->args[0];
|
||||
float star_alpha = global.plr.slaves->args[1];
|
||||
|
||||
draw_magic_star(e->pos, 0.75 * star_alpha,
|
||||
rgb(1.0, 0.1, 0.1),
|
||||
rgb(0.0, 0.1, 1.1)
|
||||
);
|
||||
|
||||
marisa_common_slave_draw(e, t);
|
||||
|
||||
if(laser_alpha <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
glColor4f(1, 1, 1, laser_alpha);
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(e->args[3]), cimag(e->args[3]), 0);
|
||||
draw_texture(0, 0, "part/lasercurve");
|
||||
glPopMatrix();
|
||||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
static void marisa_laser_fader_draw(Enemy *e, int t) {
|
||||
}
|
||||
|
||||
static float get_laser_alpha(Enemy *e, float a) {
|
||||
if(e->draw_rule == marisa_laser_fader_draw) {
|
||||
return e->args[1];
|
||||
}
|
||||
|
||||
return min(a, min(1, (global.frames - e->birthtime) * 0.1));
|
||||
}
|
||||
|
||||
#define FOR_EACH_SLAVE(e) for(Enemy *e = global.plr.slaves; e; e = e->next) if(e != renderer)
|
||||
#define FOR_EACH_REAL_SLAVE(e) FOR_EACH_SLAVE(e) if(e->draw_rule == marisa_laser_slave_draw)
|
||||
|
||||
static void marisa_laser_renderer_draw(Enemy *renderer, int t) {
|
||||
double a = creal(renderer->args[0]);
|
||||
Shader *shader = get_shader("marisa_laser");
|
||||
int u_clr = uniloc(shader, "color");
|
||||
int u_alpha = uniloc(shader, "alphamod");
|
||||
int u_length = uniloc(shader, "length");
|
||||
// int u_cutoff = uniloc(shader, "cutoff");
|
||||
Texture *tex0 = get_tex("part/marisa_laser0");
|
||||
Texture *tex1 = get_tex("part/marisa_laser1");
|
||||
|
||||
glUseProgram(shader->prog);
|
||||
glUniform4f(u_clr, 1, 1, 1, 1);
|
||||
glBlendFunc(GL_SRC_COLOR, GL_ONE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.rgba[0].fbo);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glBlendEquation(GL_MAX);
|
||||
|
||||
FOR_EACH_SLAVE(e) {
|
||||
if(set_alpha(u_alpha, get_laser_alpha(e, a))) {
|
||||
draw_laser_beam(e->pos, e->args[3], 32, 128, -0.02 * t, tex1, u_length);
|
||||
}
|
||||
}
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glUseProgram(0);
|
||||
draw_fbo_viewport(&resources.fbo.rgba[0]);
|
||||
glUseProgram(shader->prog);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
glUniform4f(u_clr, 1.0, 0.4, 0.0, 1.0);
|
||||
FOR_EACH_SLAVE(e) {
|
||||
if(set_alpha_dimmed(u_alpha, get_laser_alpha(e, a))) {
|
||||
draw_laser_beam(e->pos, e->args[3], 40, 128, t * -0.05, tex0, u_length);
|
||||
}
|
||||
}
|
||||
|
||||
glUniform4f(u_clr, 0.1, 0.1, 1.0, 1.0);
|
||||
FOR_EACH_SLAVE(e) {
|
||||
if(set_alpha_dimmed(u_alpha, get_laser_alpha(e, a))) {
|
||||
draw_laser_beam(e->pos, e->args[3], 30, 128, t * 0.025, tex0, u_length);
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
static int marisa_laser_fader(Enemy *e, int t) {
|
||||
e->args[1] = approach(e->args[1], 0.0, 0.1);
|
||||
|
||||
if(creal(e->args[1]) == 0) {
|
||||
return ACTION_DESTROY;
|
||||
|
||||
float angle = creal(p->args[2]);
|
||||
float factor = (1-global.plr.focus/30.0) * !!angle;
|
||||
complex dir = -cexp(I*((angle+0.125*sin(global.frames/25.0)*(angle > 0? 1 : -1))*factor + M_PI/2));
|
||||
p->args[0] = 20*dir;
|
||||
linear(p, t);
|
||||
|
||||
p->pos = ((Enemy *)REF(p->args[1]))->pos + p->pos;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int marisa_laser_slave(Enemy *e, int t) {
|
||||
if(player_should_shoot(&global.plr, true)) {
|
||||
if(!(global.frames % 4))
|
||||
create_projectile_p(&global.projs, get_tex("proj/marilaser"), 0, 0, marisa_laser_draw, marisa_laser, 0, add_ref(e),e->args[2],0)->type = PlrProj+e->args[1]*4;
|
||||
static Enemy* spawn_laser_fader(Enemy *e, double alpha) {
|
||||
return create_enemy_p(&global.plr.slaves, e->pos, ENEMY_IMMUNE, marisa_laser_fader_draw, marisa_laser_fader,
|
||||
e->args[0], alpha, e->args[2], e->args[3]);
|
||||
}
|
||||
|
||||
if(!(global.frames % 3)) {
|
||||
float s = 0.5 + 0.3*sin(global.frames/7.0);
|
||||
create_particle3c("marilaser_part0", 0, rgb(1-s,0.5,s), PartDraw, marisa_laser, 0, add_ref(e), e->args[2])->type=PlrProj;
|
||||
static int marisa_laser_renderer(Enemy *renderer, int t) {
|
||||
if(player_should_shoot(&global.plr, true) && renderer->next) {
|
||||
renderer->args[0] = approach(renderer->args[0], 1.0, 0.2);
|
||||
renderer->args[1] = approach(renderer->args[1], 1.0, 0.2);
|
||||
renderer->args[2] = 1;
|
||||
} else {
|
||||
if(creal(renderer->args[2])) {
|
||||
FOR_EACH_REAL_SLAVE(e) {
|
||||
spawn_laser_fader(e, renderer->args[0]);
|
||||
}
|
||||
|
||||
renderer->args[2] = 0;
|
||||
}
|
||||
create_particle1c("lasercurve", e->pos, 0, Fade, timeout, 4)->type = PlrProj;
|
||||
|
||||
renderer->args[0] = 0;
|
||||
renderer->args[1] = approach(renderer->args[1], 0.0, 0.1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef FOR_EACH_SLAVE
|
||||
#undef FOR_EACH_REAL_SLAVE
|
||||
|
||||
static int marisa_laser_slave(Enemy *e, int t) {
|
||||
if(t == EVENT_DEATH && !global.game_over && global.plr.slaves && creal(global.plr.slaves->args[0])) {
|
||||
spawn_laser_fader(e, global.plr.slaves->args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(t < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
e->pos = global.plr.pos + (1 - global.plr.focus/30.0)*e->pos0 + (global.plr.focus/30.0)*e->args[0];
|
||||
|
||||
if(player_should_shoot(&global.plr, true)) {
|
||||
float angle = creal(e->args[2]);
|
||||
float f = smoothreclamp(global.plr.focus, 0, 30, 0, 1);
|
||||
f = smoothreclamp(f, 0, 1, 0, 1);
|
||||
float factor = (1.0 + 0.7 * psin(t/15.0)) * -(1-f) * !!angle;
|
||||
e->args[3] = trace_laser(e->pos, -5 * cexp(I*(angle*factor + M_PI/2)), creal(e->args[1]));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -136,39 +340,50 @@ static void marisa_laser_bomb(Player *plr) {
|
|||
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_BOMB, masterspark_draw, masterspark, 280,0,0,0);
|
||||
}
|
||||
|
||||
static void marisa_laser_power(Player *plr, short npow) {
|
||||
static void marisa_laser_respawn_slaves(Player *plr, short npow) {
|
||||
Enemy *e = plr->slaves, *tmp;
|
||||
double dmg = 4;
|
||||
|
||||
if(plr->power / 100 == npow / 100)
|
||||
return;
|
||||
|
||||
while(e != 0) {
|
||||
tmp = e;
|
||||
e = e->next;
|
||||
if(tmp->hp == ENEMY_IMMUNE)
|
||||
if(tmp->logic_rule == marisa_laser_slave) {
|
||||
delete_enemy(&plr->slaves, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if(npow / 100 == 1) {
|
||||
create_enemy_p(&plr->slaves, -40.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, -40.0*I, dmg, 0, 0);
|
||||
create_enemy_p(&plr->slaves, -40.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, -40.0*I, dmg, 0, 0);
|
||||
}
|
||||
|
||||
if(npow >= 200) {
|
||||
create_enemy_p(&plr->slaves, 25-5.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, 8-40.0*I, dmg, -M_PI/30, 0);
|
||||
create_enemy_p(&plr->slaves, -25-5.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, -8-40.0*I, dmg, M_PI/30, 0);
|
||||
create_enemy_p(&plr->slaves, 25-5.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, 8-40.0*I, dmg, -M_PI/30, 0);
|
||||
create_enemy_p(&plr->slaves, -25-5.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, -8-40.0*I, dmg, M_PI/30, 0);
|
||||
}
|
||||
|
||||
if(npow / 100 == 3) {
|
||||
create_enemy_p(&plr->slaves, -30.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, -50.0*I, dmg, 0, 0);
|
||||
create_enemy_p(&plr->slaves, -30.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, -50.0*I, dmg, 0, 0);
|
||||
}
|
||||
|
||||
if(npow >= 400) {
|
||||
create_enemy_p(&plr->slaves, 17-30.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, 4-45.0*I, dmg, M_PI/60, 0);
|
||||
create_enemy_p(&plr->slaves, -17-30.0*I, ENEMY_IMMUNE, marisa_common_slave_draw, marisa_laser_slave, -4-45.0*I, dmg, -M_PI/60, 0);
|
||||
create_enemy_p(&plr->slaves, 17-30.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, 4-45.0*I, dmg, M_PI/60, 0);
|
||||
create_enemy_p(&plr->slaves, -17-30.0*I, ENEMY_IMMUNE, marisa_laser_slave_draw, marisa_laser_slave, -4-45.0*I, dmg, -M_PI/60, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void marisa_laser_power(Player *plr, short npow) {
|
||||
if(plr->power / 100 == npow / 100) {
|
||||
return;
|
||||
}
|
||||
|
||||
marisa_laser_respawn_slaves(plr, npow);
|
||||
}
|
||||
|
||||
static void marisa_laser_init(Player *plr) {
|
||||
create_enemy_p(&plr->slaves, 0, ENEMY_IMMUNE, marisa_laser_renderer_draw, marisa_laser_renderer, 0, 0, 0, 0);
|
||||
marisa_laser_respawn_slaves(plr, plr->power);
|
||||
}
|
||||
|
||||
static double marisa_laser_speed_mod(Player *plr, double speed) {
|
||||
if(global.frames - plr->recovery < 0) {
|
||||
speed /= 5.0;
|
||||
|
@ -181,11 +396,18 @@ static void marisa_laser_preload(void) {
|
|||
const int flags = RESF_DEFAULT;
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
"part/marilaser_part0",
|
||||
"proj/marilaser",
|
||||
// "part/marilaser_part0",
|
||||
// "proj/marilaser",
|
||||
"proj/marisa",
|
||||
"masterspark",
|
||||
"masterspark_ring",
|
||||
"part/marisa_laser0",
|
||||
"part/marisa_laser1",
|
||||
"part/magic_star",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, flags,
|
||||
"marisa_laser",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, flags | RESF_OPTIONAL,
|
||||
|
@ -203,5 +425,6 @@ PlayerMode plrmode_marisa_a = {
|
|||
.power = marisa_laser_power,
|
||||
.speed_mod = marisa_laser_speed_mod,
|
||||
.preload = marisa_laser_preload,
|
||||
.init = marisa_laser_init,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -117,14 +117,10 @@ static void marisa_star_bomb(Player *plr) {
|
|||
}
|
||||
}
|
||||
|
||||
static void marisa_star_power(Player *plr, short npow) {
|
||||
static void marisa_star_respawn_slaves(Player *plr, short npow) {
|
||||
Enemy *e = plr->slaves, *tmp;
|
||||
double dmg = 5;
|
||||
|
||||
if(plr->power / 100 == npow / 100) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(e != 0) {
|
||||
tmp = e;
|
||||
e = e->next;
|
||||
|
@ -151,6 +147,18 @@ static void marisa_star_power(Player *plr, short npow) {
|
|||
}
|
||||
}
|
||||
|
||||
static void marisa_star_power(Player *plr, short npow) {
|
||||
if(plr->power / 100 == npow / 100) {
|
||||
return;
|
||||
}
|
||||
|
||||
marisa_star_respawn_slaves(plr, npow);
|
||||
}
|
||||
|
||||
static void marisa_star_init(Player *plr) {
|
||||
marisa_star_respawn_slaves(plr, plr->power);
|
||||
}
|
||||
|
||||
static void marisa_star_preload(void) {
|
||||
const int flags = RESF_DEFAULT;
|
||||
|
||||
|
@ -174,5 +182,6 @@ PlayerMode plrmode_marisa_b = {
|
|||
.shot = marisa_common_shot,
|
||||
.power = marisa_star_power,
|
||||
.preload = marisa_star_preload,
|
||||
.init = marisa_star_init,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -160,12 +160,8 @@ static void youmu_mirror_bomb(Player *plr) {
|
|||
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_BOMB, NULL, youmu_split, 280,0,0,0);
|
||||
}
|
||||
|
||||
static void youmu_mirror_think(Player *plr) {
|
||||
// XXX: do we really have to do this every frame?
|
||||
|
||||
if(plr->slaves == NULL) {
|
||||
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_IMMUNE, myon_draw, youmu_mirror_myon, 0, 0, 0, 0);
|
||||
}
|
||||
static void youmu_mirror_init(Player *plr) {
|
||||
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_IMMUNE, myon_draw, youmu_mirror_myon, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void youmu_mirror_preload(void) {
|
||||
|
@ -188,7 +184,7 @@ PlayerMode plrmode_youmu_a = {
|
|||
.procs = {
|
||||
.bomb = youmu_mirror_bomb,
|
||||
.shot = youmu_common_shot,
|
||||
.think = youmu_mirror_think,
|
||||
.init = youmu_mirror_init,
|
||||
.preload = youmu_mirror_preload,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -100,6 +100,7 @@ int collision_projectile(Projectile *p) {
|
|||
int damage = p->type - PlrProj;
|
||||
|
||||
while(e != NULL) {
|
||||
// XXX: this 'hitbox' radius is smaller than the fairy circle, we should probably increase it...
|
||||
if(e->hp != ENEMY_IMMUNE && cabs(e->pos - p->pos) < 15) {
|
||||
player_add_points(&global.plr, damage * 0.5);
|
||||
|
||||
|
@ -136,6 +137,18 @@ void draw_projectiles(Projectile *projs) {
|
|||
|
||||
}
|
||||
|
||||
bool projectile_in_viewport(Projectile *proj) {
|
||||
int e = proj->maxviewportdist;
|
||||
|
||||
if(e < 300 && (proj->type == Particle || proj->type >= PlrProj)) {
|
||||
// XXX: maybe have them set it manually?
|
||||
e = 300;
|
||||
}
|
||||
|
||||
return !(creal(proj->pos) + proj->tex->w/2 + e < 0 || creal(proj->pos) - proj->tex->w/2 - e > VIEWPORT_W
|
||||
|| cimag(proj->pos) + proj->tex->h/2 + e < 0 || cimag(proj->pos) - proj->tex->h/2 - e > VIEWPORT_H);
|
||||
}
|
||||
|
||||
void process_projectiles(Projectile **projs, bool collision) {
|
||||
Projectile *proj = *projs, *del = NULL;
|
||||
|
||||
|
@ -164,18 +177,9 @@ void process_projectiles(Projectile **projs, bool collision) {
|
|||
}
|
||||
|
||||
if(col == 1 && global.frames - abs(global.plr.recovery) >= 0)
|
||||
player_death(&global.plr);
|
||||
player_death(&global.plr);
|
||||
|
||||
int e = proj->maxviewportdist;
|
||||
|
||||
if(e < 300 && (proj->type == Particle || proj->type >= PlrProj)) {
|
||||
// XXX: maybe have them set it manually?
|
||||
e = 300;
|
||||
}
|
||||
|
||||
if(action == ACTION_DESTROY || col
|
||||
|| creal(proj->pos) + proj->tex->w/2 + e < 0 || creal(proj->pos) - proj->tex->w/2 - e > VIEWPORT_W
|
||||
|| cimag(proj->pos) + proj->tex->h/2 + e < 0 || cimag(proj->pos) - proj->tex->h/2 - e > VIEWPORT_H) {
|
||||
if(action == ACTION_DESTROY || col || !projectile_in_viewport(proj)) {
|
||||
del = proj;
|
||||
proj = proj->next;
|
||||
delete_projectile(projs, del);
|
||||
|
|
|
@ -71,6 +71,7 @@ void delete_projectile(Projectile **dest, Projectile *proj);
|
|||
void delete_projectiles(Projectile **dest);
|
||||
void draw_projectiles(Projectile *projs);
|
||||
int collision_projectile(Projectile *p);
|
||||
bool projectile_in_viewport(Projectile *proj);
|
||||
void process_projectiles(Projectile **projs, bool collision);
|
||||
|
||||
Projectile *get_proj(Projectile *hay, int birthtime);
|
||||
|
|
|
@ -445,6 +445,8 @@ void free_resources(bool all) {
|
|||
delete_fbo(&resources.fbo.bg[1]);
|
||||
delete_fbo(&resources.fbo.fg[0]);
|
||||
delete_fbo(&resources.fbo.fg[1]);
|
||||
delete_fbo(&resources.fbo.rgba[0]);
|
||||
delete_fbo(&resources.fbo.rgba[1]);
|
||||
|
||||
if(!getenvint("TAISEI_NOASYNC", 0)) {
|
||||
events_unregister_handler(resource_asyncload_handler);
|
||||
|
|
|
@ -103,6 +103,7 @@ typedef struct Resources {
|
|||
struct {
|
||||
FBO bg[2];
|
||||
FBO fg[2];
|
||||
FBO rgba[2]; // XXX: do we actually need 2 RGBA FBOs?
|
||||
} fbo;
|
||||
} Resources;
|
||||
|
||||
|
|
|
@ -82,8 +82,8 @@ int sign(double) __attribute__((const));
|
|||
double swing(double x, double s) __attribute__((const));
|
||||
unsigned int topow2(unsigned int x) __attribute__((const));
|
||||
float ftopow2(float x) __attribute__((const));
|
||||
float smooth(float x);
|
||||
float smoothreclamp(float x, float old_min, float old_max, float new_min, float new_max);
|
||||
float smooth(float x) __attribute__((const));
|
||||
float smoothreclamp(float x, float old_min, float old_max, float new_min, float new_max) __attribute__((const));
|
||||
|
||||
//
|
||||
// gl/video utils
|
||||
|
|
10
src/video.c
10
src/video.c
|
@ -173,10 +173,12 @@ static void video_update_quality(void) {
|
|||
|
||||
log_debug("q:%f, fg:%f, bg:%f, text:%f", q, fg, bg, text);
|
||||
|
||||
reinit_fbo(&resources.fbo.bg[0], bg);
|
||||
reinit_fbo(&resources.fbo.bg[1], bg);
|
||||
reinit_fbo(&resources.fbo.fg[0], fg);
|
||||
reinit_fbo(&resources.fbo.fg[1], fg);
|
||||
reinit_fbo(&resources.fbo.bg[0], bg, GL_RGB);
|
||||
reinit_fbo(&resources.fbo.bg[1], bg, GL_RGB);
|
||||
reinit_fbo(&resources.fbo.fg[0], fg, GL_RGB);
|
||||
reinit_fbo(&resources.fbo.fg[1], fg, GL_RGB);
|
||||
reinit_fbo(&resources.fbo.rgba[0], fg, GL_RGBA);
|
||||
reinit_fbo(&resources.fbo.rgba[1], fg, GL_RGBA);
|
||||
|
||||
reload_fonts(text);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue