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
|
@ -8,6 +8,7 @@ atlases = [
|
|||
'common_ui',
|
||||
'huge',
|
||||
'portraits',
|
||||
'reimu',
|
||||
]
|
||||
|
||||
atlas_common_args = [
|
||||
|
|
3
atlas/overrides/part/fantasyseal_impact.spr
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
w = 128
|
||||
h = 128
|
4
atlas/overrides/part/ofuda_glow.spr
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
w = 20
|
||||
h = 30
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
#w = 76
|
||||
#h = 95
|
||||
|
||||
w = 48
|
||||
h = 60
|
||||
|
|
3
atlas/overrides/player/reimu.framegroup.spr
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
w = 54
|
||||
h = 66
|
4
atlas/overrides/proj/hakurei_seal.spr
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
w = 16
|
||||
h = 39
|
||||
|
4
atlas/overrides/proj/needle.spr
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
w = 14
|
||||
h = 72
|
||||
|
3
atlas/overrides/proj/needle2.spr
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
w = 7
|
||||
h = 65
|
4
atlas/overrides/proj/ofuda.spr
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
w = 16
|
||||
h = 26
|
||||
|
3
atlas/overrides/yinyang.spr
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
w = 24
|
||||
h = 24
|
BIN
atlas/reimu/part/fantasyseal_impact.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
atlas/reimu/part/ofuda_glow.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
atlas/reimu/player/reimu.frame0000.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
atlas/reimu/player/reimu.frame0001.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
atlas/reimu/player/reimu.frame0002.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
atlas/reimu/player/reimu.frame0003.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
atlas/reimu/player/reimu.frame0004.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
atlas/reimu/player/reimu.frame0005.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
atlas/reimu/player/reimu.frame0006.png
Normal file
After Width: | Height: | Size: 4 KiB |
BIN
atlas/reimu/player/reimu.frame0007.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
atlas/reimu/player/reimu.frame0008.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
atlas/reimu/player/reimu.frame0009.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
atlas/reimu/player/reimu.frame0010.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
atlas/reimu/player/reimu.frame0011.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
atlas/reimu/proj/glowball.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
atlas/reimu/proj/hakurei_seal.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
atlas/reimu/proj/needle.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
atlas/reimu/proj/needle2.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
atlas/reimu/proj/ofuda.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
atlas/reimu/yinyang.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
|
@ -58,6 +58,67 @@
|
|||
================================================================================
|
||||
|
||||
|
||||
○ Hakurei Reimu
|
||||
|
||||
For Reimu, today should have been a peaceful day. It was spring, so early
|
||||
mornings were still chilly and flowers were just beginning to burst into
|
||||
bright blooms around the shrine. But unfortunately, Reimu did not get to
|
||||
enjoy her luxury of sleeping in as she was rudely awoken by insistent
|
||||
prodding into her cheek.
|
||||
|
||||
“Mmmh?”
|
||||
|
||||
“Wake up, Reimu. There is a serious incident unraveling itself as we speak!”
|
||||
|
||||
Although annoyed at being woken up in her own shrine, she nevertheless
|
||||
cracked an unamused eye open to stare at her beauty sleep’s disturbance. The
|
||||
voice was familiar, and so was the tall, unsettling woman peering back at
|
||||
her from her own personal crack of distorted reality.
|
||||
|
||||
“What now, Yukari? Can’t you see I am doing the important duty of self-care
|
||||
as a shrine maiden?”
|
||||
|
||||
“You should think about switching duties then,” Yukari quipped back,
|
||||
reaching over to outright pinch Reimu’s cheek. “The barrier is being
|
||||
distorted by someone with a great deal of unexpected power, and it is of a
|
||||
sort that I cannot manipulate.”
|
||||
|
||||
“So, you can’t fix it, then?”
|
||||
|
||||
“Of course not. It’s too… logical. Even though I created this barrier with
|
||||
mathematics in mind, my parameters were fictional. It’s a power grounded in
|
||||
reality, and it seems to have outright torn open a hole in the barrier up on
|
||||
Yōkai Mountain, creating a tunnel to somewhere else entirely.”
|
||||
|
||||
Now fully awake, Reimu sat up and batted Yukari’s intrusive hands away. But
|
||||
even though she sincerely wanted to ignore the yōkai sage that plagued her
|
||||
life as a constant irritation, she too could feel something off in the air.
|
||||
The Hakurei Shrine sat at the very edge of Gensōkyō, and it held the barrier
|
||||
steady as a medium between both sides of the boundary. Items from the
|
||||
Outside World commonly ended up strewn around the grounds, and so did the
|
||||
occasional high school girl as well. Despite the unusual atmosphere of the
|
||||
shrine, Reimu immediately knew just by glancing around that it was not
|
||||
normal for her shrine’s walls to look patchy and moldy in places, or for the
|
||||
floor to have random cracks and stains not present from everyday use.
|
||||
|
||||
“You can see it, can you not? The Hakurei Shrine from the Outside World is
|
||||
merging with ours as our fantasy disappears. Soon it will replace yours
|
||||
entirely, and you will live in the broken down version of your beloved
|
||||
home.”
|
||||
|
||||
That was all it took to get Reimu in action as she slipped into her uniform
|
||||
and grabbed her Yin-Yang Orbs and purification rod. Although the weakening
|
||||
of the Hakurei Barrier was worrying enough on its own, there was no way she
|
||||
could allow her shrine to turn into the run-down mess it was on the other
|
||||
side of the border. Whoever was behind this needed to stop, for her sake and
|
||||
everyone else’s. And if nothing else, the shrine maiden was loath to become
|
||||
homeless. That simply would not do.
|
||||
|
||||
“Yukari, you’ll take me there, won’t you?”
|
||||
|
||||
Unfortunately for the shrine maiden, she was met with silence. It seemed as
|
||||
though she would have to take the long route to Yōkai Mountain.
|
||||
|
||||
○ Kirisame Marisa
|
||||
|
||||
Early one spring day, just after dawn had passed, Marisa was finding a
|
||||
|
|
BIN
resources/gfx/atlas_reimu_0.png
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
resources/gfx/dialog/reimu.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
resources/gfx/gaplight.png
Normal file
After Width: | Height: | Size: 243 KiB |
2
resources/gfx/gaplight.tex
Normal file
|
@ -0,0 +1,2 @@
|
|||
wrap_t = mirror
|
||||
wrap_s = clamp
|
12
resources/gfx/part/fantasyseal_impact.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1
|
||||
region_y = 1
|
||||
region_w = 256
|
||||
region_h = 256
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 128
|
||||
h = 128
|
12
resources/gfx/part/ofuda_glow.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1731
|
||||
region_y = 1
|
||||
region_w = 80
|
||||
region_h = 120
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 20
|
||||
h = 30
|
12
resources/gfx/player/reimu.ani
Normal file
|
@ -0,0 +1,12 @@
|
|||
@sprite_count = 11
|
||||
|
||||
main = d10 4 5 6 7
|
||||
left = m d10 0 1 2 3
|
||||
right = d10 0 1 2 3
|
||||
|
||||
main2left = m d2 8 9 10
|
||||
main2right = d2 8 9 10
|
||||
left2main = m d2 10 9
|
||||
left2right = m d2 10 9 m 8 9 10
|
||||
right2main = d2 10 9
|
||||
right2left = d2 10 9 m 8 9 10
|
12
resources/gfx/player/reimu.frame0000.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 411
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0001.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 521
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0002.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 631
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0003.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 741
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0004.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 851
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0005.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 961
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0006.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1071
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0007.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1181
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0008.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1291
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0009.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1401
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0010.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1511
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
12
resources/gfx/player/reimu.frame0011.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1621
|
||||
region_y = 1
|
||||
region_w = 108
|
||||
region_h = 132
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 54
|
||||
h = 66
|
7
resources/gfx/proj/glowball.spr
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 259
|
||||
region_y = 1
|
||||
region_w = 150
|
||||
region_h = 150
|
12
resources/gfx/proj/hakurei_seal.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1813
|
||||
region_y = 1
|
||||
region_w = 64
|
||||
region_h = 156
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 16
|
||||
h = 39
|
12
resources/gfx/proj/needle.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 2011
|
||||
region_y = 1
|
||||
region_w = 28
|
||||
region_h = 144
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 14
|
||||
h = 72
|
12
resources/gfx/proj/needle2.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 2041
|
||||
region_y = 1
|
||||
region_w = 14
|
||||
region_h = 130
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 7
|
||||
h = 65
|
12
resources/gfx/proj/ofuda.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1879
|
||||
region_y = 1
|
||||
region_w = 64
|
||||
region_h = 104
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 16
|
||||
h = 26
|
BIN
resources/gfx/runes.png
Normal file
After Width: | Height: | Size: 473 KiB |
12
resources/gfx/yinyang.spr
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_reimu_0
|
||||
region_x = 1945
|
||||
region_y = 1
|
||||
region_w = 64
|
||||
region_h = 64
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 24
|
||||
h = 24
|
BIN
resources/sfx/bomb_reimu_a.ogg
Normal file
|
@ -33,3 +33,4 @@ warp = 80
|
|||
damage_feedback = 120
|
||||
hit0 = 120
|
||||
hit1 = 120
|
||||
bomb_reimu_a = 128
|
||||
|
|
|
@ -48,4 +48,33 @@ vec4 color_mul_alpha(vec4 c) {
|
|||
return vec4(c.rgb * c.a, c.a);
|
||||
}
|
||||
|
||||
mat2 rot(float a) {
|
||||
return mat2(cos(a), -sin(a), sin(a), cos(a));
|
||||
}
|
||||
|
||||
float line_segment(vec2 p, vec2 a, vec2 b, float thickness) {
|
||||
vec2 pa = p - a;
|
||||
vec2 ba = b - a;
|
||||
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
|
||||
return smoothstep(thickness, 0.0, length(pa - ba*h));
|
||||
}
|
||||
|
||||
// Taken from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl
|
||||
|
||||
vec3 rgb2hsv(vec3 c) {
|
||||
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
|
||||
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
|
||||
|
||||
float d = q.x - min(q.w, q.y);
|
||||
float e = 1.0e-10;
|
||||
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||
}
|
||||
|
||||
vec3 hsv2rgb(vec3 c) {
|
||||
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,11 +16,15 @@ glsl_files = files(
|
|||
'ingame_menu.frag.glsl',
|
||||
'laser_generic.vert.glsl',
|
||||
'marisa_hakkero.frag.glsl',
|
||||
'marisa_hakkero.vert.glsl',
|
||||
'marisa_laser.frag.glsl',
|
||||
'maristar_bombbg.frag.glsl',
|
||||
'masterspark.frag.glsl',
|
||||
'max_to_alpha.frag.glsl',
|
||||
'player_death.frag.glsl',
|
||||
'reimu_bomb_bg.frag.glsl',
|
||||
'reimu_gap.frag.glsl',
|
||||
'reimu_gap_light.frag.glsl',
|
||||
'spellcard_intro.frag.glsl',
|
||||
'spellcard_outro.frag.glsl',
|
||||
'spellcard_walloftext.frag.glsl',
|
||||
|
@ -36,6 +40,7 @@ glsl_files = files(
|
|||
'sprite_negative.frag.glsl',
|
||||
'sprite_silhouette.frag.glsl',
|
||||
'sprite_silhouette.vert.glsl',
|
||||
'sprite_yinyang.frag.glsl',
|
||||
'sprite_youmu_charged_shot.frag.glsl',
|
||||
'sprite_youmu_charged_shot.vert.glsl',
|
||||
'sprite_youmu_myon_shot.frag.glsl',
|
||||
|
|
122
resources/shader/reimu_bomb_bg.frag.glsl
Normal file
|
@ -0,0 +1,122 @@
|
|||
#version 330 core
|
||||
|
||||
#include "interface/standard.glslh"
|
||||
#include "lib/util.glslh"
|
||||
#include "lib/render_context.glslh"
|
||||
|
||||
UNIFORM(1) vec2 aspect;
|
||||
UNIFORM(2) float zoom;
|
||||
UNIFORM(3) float time;
|
||||
UNIFORM(4) sampler2D runes;
|
||||
|
||||
float _split(float x) {
|
||||
return sqrt(0.25 - pow(x - 0.5, 2));
|
||||
}
|
||||
|
||||
vec2 runes_transform_uv(vec2 uv) {
|
||||
const float segments = 32;
|
||||
uv.y = mod(uv.y, 1.0);
|
||||
uv.y += floor(uv.x);
|
||||
uv.y /= segments;
|
||||
return uv;
|
||||
}
|
||||
|
||||
float split(float x) {
|
||||
/*
|
||||
if(x <= 0.25) {
|
||||
return 0.25;
|
||||
}
|
||||
|
||||
if(x >= 0.75) {
|
||||
return 0.75;
|
||||
}
|
||||
*/
|
||||
|
||||
if(x < 0.5) {
|
||||
x = 1.0 - _split(2 * x) - 0.5;
|
||||
} else {
|
||||
x = _split(2 * x - 1) + 0.5;
|
||||
}
|
||||
|
||||
return 0.5 * x + 0.25;
|
||||
}
|
||||
|
||||
float yinyang(vec2 uv, out float light_dist, out float dark_dist) {
|
||||
float s = split(uv.x);
|
||||
float v;
|
||||
|
||||
v = smoothstep(0.0, 0.01, uv.y - s);
|
||||
light_dist = length((uv - vec2(0.75, 0.5)) * 16.0);
|
||||
v = mix(v, 1.0, smoothstep(1.0, 0.95, light_dist));
|
||||
dark_dist = length((uv - vec2(0.25, 0.5)) * 16.0);
|
||||
v = mix(v, 0.0, smoothstep(1.0, 0.95, dark_dist));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
float yinyang_spin(vec2 uv, vec2 aspect, float a, out float light_dist, out float dark_dist) {
|
||||
mat2 r = rot(a);
|
||||
uv -= 0.5;
|
||||
uv *= aspect;
|
||||
uv *= r;
|
||||
uv += 0.5;
|
||||
return yinyang(uv, light_dist, dark_dist);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 uv = texCoord;
|
||||
float ld, dd;
|
||||
|
||||
float yy = yinyang_spin(uv, aspect * zoom, -time, ld, dd);
|
||||
|
||||
vec2 uv_r = uv;
|
||||
vec2 uv_g = uv;
|
||||
vec2 uv_b = uv;
|
||||
|
||||
vec3 c = vec3(0);
|
||||
float rfactor = sqrt(dd*dd + ld*ld) * 0.01 * yy;
|
||||
float kek = (1 - 2 * yy);
|
||||
|
||||
ld = sqrt(ld);
|
||||
dd = sqrt(dd);
|
||||
|
||||
mat2 m_r = rot(dd * 0.00005 * kek) / (1 + ld * -0.0006 * kek);
|
||||
mat2 m_g = rot(dd * 0.00009 * kek) / (1 + ld * -0.0004 * kek);
|
||||
mat2 m_b = rot(dd * 0.00012 * kek) / (1 + ld * -0.0002 * kek);
|
||||
|
||||
const int samples = 24;
|
||||
const float isamples = 1.0 / samples;
|
||||
|
||||
for(int i = 0; i < samples; ++i) {
|
||||
uv_r -= 0.5;
|
||||
uv_r *= m_r;
|
||||
uv_r += 0.5;
|
||||
c.r += texture(tex, uv_r).r;
|
||||
|
||||
uv_g -= 0.5;
|
||||
uv_g *= m_g;
|
||||
uv_g += 0.5;
|
||||
c.g += texture(tex, uv_g).g;
|
||||
|
||||
uv_b -= 0.5;
|
||||
uv_b *= m_b;
|
||||
uv_b += 0.5;
|
||||
c.b += texture(tex, uv_b).b;
|
||||
}
|
||||
|
||||
fragColor = vec4(c * isamples, 1) * 0.9 * mix(r_color, vec4(r_color.a), 1);
|
||||
|
||||
const float rune_lines = 24;
|
||||
|
||||
vec2 runes_uv = (uv - 0.5) * rot(pi * 0.5) + 0.5;
|
||||
float line = floor(runes_uv.y * rune_lines);
|
||||
runes_uv.x += 0.931223 * line + time * 0.1 * cos(pi * line);
|
||||
runes_uv.y *= -rune_lines;
|
||||
runes_uv = runes_transform_uv(runes_uv);
|
||||
|
||||
float rune_factor = texture(runes, runes_uv).r;
|
||||
fragColor.rgb = pow(fragColor.rgb, vec3(1 + (1 - 2 * rune_factor) * 0.1));
|
||||
// fragColor = mix(fragColor, 0.9 * fragColor + vec4(0.1), rune_factor * r_color);
|
||||
fragColor += r_color * rune_factor * 0.1;
|
||||
fragColor.a *= (1 - rune_factor * 0.1);
|
||||
}
|
2
resources/shader/reimu_bomb_bg.prog
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
glsl_objects = standard.vert reimu_bomb_bg.frag
|
77
resources/shader/reimu_gap.frag.glsl
Normal file
|
@ -0,0 +1,77 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/render_context.glslh"
|
||||
#include "interface/standard.glslh"
|
||||
#include "lib/util.glslh"
|
||||
|
||||
#define NUM_GAPS 4
|
||||
// #define DRAW_LINKS
|
||||
|
||||
UNIFORM(1) vec2 viewport;
|
||||
UNIFORM(2) float time;
|
||||
UNIFORM(3) vec2 gap_size;
|
||||
UNIFORM(4) vec2 gaps[NUM_GAPS];
|
||||
UNIFORM(8) float gap_angles[NUM_GAPS];
|
||||
UNIFORM(12) int gap_links[NUM_GAPS];
|
||||
|
||||
void main(void) {
|
||||
vec4 bg = texture(tex, texCoord);
|
||||
fragColor = bg;
|
||||
|
||||
vec2 frag_loc = texCoord * viewport;
|
||||
frag_loc.y = viewport.y - frag_loc.y;
|
||||
|
||||
float t = time * 6;
|
||||
const float mag = 0.5;
|
||||
const float pmag = 0.123;
|
||||
frag_loc.x += mag * sin(t);
|
||||
frag_loc.y += mag * sin(t * 1.22 - frag_loc.x * pmag);
|
||||
frag_loc.x += mag * sin(t * -1.36 - frag_loc.y * pmag);
|
||||
frag_loc.y += mag * sin(t * -1.29 - frag_loc.x * pmag);
|
||||
frag_loc.x += mag * sin(t * 1.35 - frag_loc.y * pmag);
|
||||
|
||||
const float h0 = 1;
|
||||
const float h1 = h0 * 0.8;
|
||||
const vec4 gap_color = vec4(0.75, 0, 0.4, 1);
|
||||
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
vec2 gap = gaps[i];
|
||||
float gap_angle = gap_angles[i];
|
||||
int link = gap_links[i];
|
||||
|
||||
vec2 next_gap = gaps[link];
|
||||
float next_gap_angle = gap_angles[link];
|
||||
|
||||
mat2 gap_rot = rot(gap_angle);
|
||||
float edge = length(gap_rot * (frag_loc - gap) / gap_size);
|
||||
float gap_mask = smoothstep(h0, h1, edge);
|
||||
|
||||
vec2 tc_inv = 1 - texCoord;
|
||||
float _ = time * 0.2;//0.5 + 0.5 * sin(time);
|
||||
|
||||
vec2 tc = vec2(texCoord.x, 1 - texCoord.y) * viewport;
|
||||
tc -= gap.xy;
|
||||
tc *= rot((next_gap_angle - gap_angle));
|
||||
tc += next_gap.xy;
|
||||
tc /= viewport;
|
||||
tc.y = 1 - tc.y;
|
||||
|
||||
fragColor = mix(fragColor, mix(gap_color, texture(tex, tc), 1 - pow(edge, 3)), gap_mask);
|
||||
}
|
||||
|
||||
#ifdef DRAW_LINKS
|
||||
for(int i = 0; i < NUM_GAPS; ++i) {
|
||||
vec2 gap = gaps[i];
|
||||
float gap_angle = gap_angles[i];
|
||||
int link = gap_links[i];
|
||||
|
||||
vec2 next_gap = gaps[link];
|
||||
float next_gap_angle = gap_angles[link];
|
||||
|
||||
vec2 l = texCoord * viewport;
|
||||
l.y = viewport.y - l.y;
|
||||
|
||||
fragColor = mix(fragColor, vec4(float(i&1), i/float(NUM_GAPS-1), 1-i/float(NUM_GAPS-1), 1), line_segment(l, gap, next_gap, 1));
|
||||
}
|
||||
#endif
|
||||
}
|
2
resources/shader/reimu_gap.prog
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
glsl_objects = standard.vert reimu_gap.frag
|
50
resources/shader/reimu_gap_light.frag.glsl
Normal file
|
@ -0,0 +1,50 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/render_context.glslh"
|
||||
#include "interface/standard.glslh"
|
||||
#include "lib/util.glslh"
|
||||
|
||||
UNIFORM(1) float time;
|
||||
UNIFORM(2) float strength;
|
||||
|
||||
float g(float x) {
|
||||
return sin(1.1 * x) * cos(1.98 * x);
|
||||
}
|
||||
|
||||
float wave(float x) {
|
||||
return g(x - 3 * g(0.6 * x) + 0.23 * g(1.2123 * x) + 0.7634 * g(1.12365 * x) + 1.541 * g(0.26 * x));
|
||||
}
|
||||
|
||||
float light_mask(vec2 tc) {
|
||||
float p = 20.0;
|
||||
|
||||
tc.x = mix(
|
||||
clamp(0.5 - 0.5 * pow(1 - tc.x * 2, p), 0.0, 0.5),
|
||||
clamp(0.5 + 0.5 * pow((tc.x - 0.5) * 2, p), 0.5, 1.0),
|
||||
step(0.5, tc.x)
|
||||
);
|
||||
|
||||
return smoothstep(1.0, 0.0, length((tc - 0.5) * 2.0));
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
float s = 0.6;
|
||||
float l = 1.0;
|
||||
float o = 0.123 * texCoord.x;
|
||||
|
||||
vec4 layer0 = texture(tex, texCoord + vec2(0, 0.23134 * time)) * vec4(hsv2rgb(vec3(time + (texCoord.y + 1*o), s, l)), 1);
|
||||
layer0 *= pow(0.5 + 0.5 * wave(3215*pi + 0.9314*texCoord.y - time * 0.46), 1.0);
|
||||
|
||||
vec4 layer1 = texture(tex, texCoord + vec2(0, 0.32155 * time)) * vec4(hsv2rgb(vec3(time - (texCoord.y + 2*o), s, l)), 1);
|
||||
layer1 *= pow(0.5 + 0.5 * wave(7234*pi + 0.9612*texCoord.y + time * 0.64), 1.0);
|
||||
|
||||
vec4 layer2 = texture(tex, texCoord - vec2(0, 0.30133 * time)) * vec4(hsv2rgb(vec3(time + (texCoord.y + 3*o), s, l)), 1);
|
||||
layer2 *= pow(0.5 + 0.5 * wave(4312*pi + 0.9195*texCoord.y + time * 0.42), 1.0);
|
||||
|
||||
vec4 layer3 = texture(tex, texCoord - vec2(0, 0.26424 * time)) * vec4(hsv2rgb(vec3(time - (texCoord.y + 4*o), s, l)), 1);
|
||||
layer3 *= pow(0.5 + 0.5 * wave(2642*pi + 0.9195*texCoord.y + time * 0.60), 1.0);
|
||||
|
||||
float mask = light_mask(texCoord);
|
||||
fragColor = (layer0 + layer1 + layer2 + layer3) * mask * strength * (1.5 + 0.25 * sin(time));
|
||||
fragColor.a = 0;
|
||||
}
|
2
resources/shader/reimu_gap_light.prog
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
glsl_objects = standard.vert reimu_gap_light.frag
|
9
resources/shader/sprite_yinyang.frag.glsl
Normal file
|
@ -0,0 +1,9 @@
|
|||
#version 330 core
|
||||
|
||||
#include "interface/sprite.glslh"
|
||||
|
||||
void main(void) {
|
||||
vec4 texel = texture(tex, texCoord);
|
||||
fragColor.rgb = color.rgb * texel.g - vec3(0.5 * texel.r) + vec3(texel.b);
|
||||
fragColor.a = texel.a * color.a;
|
||||
}
|
1
resources/shader/sprite_yinyang.prog
Normal file
|
@ -0,0 +1 @@
|
|||
glsl_objects = sprite_default.vert sprite_yinyang.frag
|
|
@ -489,7 +489,7 @@ static DamageResult ent_damage_boss(EntityInterface *ent, const DamageInfo *dmg)
|
|||
play_loop("hit0");
|
||||
}
|
||||
|
||||
return true;
|
||||
return DMG_RESULT_OK;
|
||||
}
|
||||
|
||||
static void boss_give_spell_bonus(Boss *boss, Attack *a, Player *plr) {
|
||||
|
@ -769,7 +769,7 @@ void process_boss(Boss **pboss) {
|
|||
play_sound_ex("bossdeath", BOSS_DEATH_DELAY * 2, false);
|
||||
} else {
|
||||
if(cabs(boss->pos - global.plr.pos) < 16) {
|
||||
player_death(&global.plr);
|
||||
ent_damage(&global.plr.ent, &(DamageInfo) { .type = DMG_ENEMY_COLLISION });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
dialog_src = files(
|
||||
'marisa.c',
|
||||
'reimu.c',
|
||||
'youmu.c',
|
||||
)
|
||||
|
|
34
src/ending.c
|
@ -86,6 +86,22 @@ void bad_ending_youmu(Ending *e) {
|
|||
track_ending(ENDING_BAD_2);
|
||||
}
|
||||
|
||||
void bad_ending_reimu(Ending *e) {
|
||||
add_ending_entry(e, -1, "“Now, let your mind be expanded! Do you have the potential to understand the code behind reality?”", NULL);
|
||||
add_ending_entry(e, -1, "Reimu may have been the mouthpiece of the gods, but this truth was far beyond the words they would push into her brain. Numbers overlapped endlessly and seamlessly over each other, and she quickly found herself in an inescapable mental haze. Without realizing it, she had stopped floating, and the Yin-Yang Orbs dropped uselessly alongside her, having lost all of their holy powers.", NULL);
|
||||
add_ending_entry(e, -1, "Tired of what she perceived as nonsense, she willed the numbers to end, and they did, taking any directives of the Hakurei god along with them to create an unbearable silence that drifted darkly into unconsciousness.", NULL);
|
||||
add_ending_entry(e, -1, "“Auughh!” \nBolting upwards in her futon, Reimu yelled out both in inexplicable frustration and pain as a sudden migraine woke her up on an otherwise peaceful morning. Grumbling, she glanced all around her room instinctually, as if she had seen something wrong with it before.", NULL);
|
||||
add_ending_entry(e, -1, "But it looked just the same as it normally did, even through the angry throbbing in her skull. Knowing that further sleep was impossible, however, she picked herself up and started to get ready for the rest of the day. Of course, she didn’t get too far before being interrupted by an overly familiar yōkai sage.", NULL);
|
||||
add_ending_entry(e, -1, "“What do you want?” Reimu asked grouchily, rubbing her forehead as she stared at a strangely concerned Yukari.", NULL);
|
||||
add_ending_entry(e, -1, "“Did you really defeat Wriggle as the main culprit of the incident yesterday?”", NULL);
|
||||
add_ending_entry(e, -1, "“Huh? I don’t even remember who I fought. Does it even matter?”", NULL);
|
||||
add_ending_entry(e, -1, "“Yes, it does! Because Wriggle shouldn’t have that sort of power. That means… she must be more dangerous than she has been letting on! Never mind, fufu!” ", NULL);
|
||||
add_ending_entry(e, -1, "Watching Yukari change her tone mid-sentence, Reimu felt disconcerted. The gap hag must have been onto something, but just as soon as she had realized it, that thought had been taken away by a mysterious force.", NULL);
|
||||
add_ending_entry(e, -1, "Clearly this peace she had achieved by defeating Wriggle was just a farce, but she had no idea who was really behind it. What she needed now was another chance in another time-- to find the real logical perpetrator of the incident, she would have to go back and do it all over again.", NULL);
|
||||
add_ending_entry(e, -1, "-BAD END-\nTry a clear without continues next time!", NULL);
|
||||
track_ending(ENDING_BAD_3);
|
||||
}
|
||||
|
||||
void good_ending_marisa(Ending *e) {
|
||||
add_ending_entry(e, -1, "“Now, let your mind be expanded! Do you have the potential to understand the code behind reality?”", NULL);
|
||||
add_ending_entry(e, -1, "“Ha! Who do ya take me for? Of course!”", NULL);
|
||||
|
@ -116,6 +132,24 @@ void good_ending_youmu(Ending *e) {
|
|||
track_ending(ENDING_GOOD_2);
|
||||
}
|
||||
|
||||
void good_ending_reimu(Ending *e) {
|
||||
add_ending_entry(e, -1, "“Now, let your mind be expanded! Do you have the potential to understand the code behind reality?”", NULL);
|
||||
add_ending_entry(e, -1, "“What a pointless question! Be defeated already!”", NULL);
|
||||
add_ending_entry(e, -1, "Reimu, with her straightforward clarity, was able to hold fast and ignore the barrage focused upon her mind by sealing herself off via her fantasy nature. Raising her purification rod as a command, her Yin-Ying Orbs soared into the false sky and coalesced into one, a glowing orb that quickly grew to humongous proportions.", NULL);
|
||||
add_ending_entry(e, -1, "She flicked her rod downwards, and Elly found herself facing this massive spirit orb unprepared. It plowed into her, and then also into her tower, smashing all in its path with a godly roar. When the dust and rubble settled, Reimu landed on the plains below, in front of the weakened Elly.", NULL);
|
||||
add_ending_entry(e, -1, "“Are you satisfied? You destroyed my research, my life, and my home. And for what? An illogical world fit for neither yōkai nor humans!” Elly shouted, trying to but failing to crawl towards her fallen scythe.", NULL);
|
||||
add_ending_entry(e, -1, "“That’s not true. You’re upset because you blame Gensōkyō for rejecting you when the reality is that you simply got lost, didn’t you? Gensōkyō welcomes everyone, and it will still welcome you,” Reimu replied, kicking aside Elly’s scythe before reaching out to pull her up. Elly hesitantly took it, her knees still shaking from Reimu’s spiritual blow.", NULL);
|
||||
add_ending_entry(e, -1, "“I may be able to return to Gensōkyō as a yōkai, but what will happen to my work? I was so close to the truth and you blew it all away. There's no way I could be satisfied without knowing!”", NULL);
|
||||
add_ending_entry(e, -1, "Reimu mulled over this for a moment before swinging her rod over her back, looking suddenly determined.", NULL);
|
||||
add_ending_entry(e, -1, "“This truth of yours almost pulled Gensōkyō apart. For that I’ll just have to figure out the rest in your stead and then deal with it in any way that I’ll need to. Seems like I can’t go home yet…” Reimu declared, breaking it off with a sigh at the end.", NULL);
|
||||
add_ending_entry(e, -1, "“Oh well, I’ll just make this as quick as I can. Feel free to invite yourself over to my shrine if you want. Everyone does that even if I say no, so I can’t really stop you.”", NULL);
|
||||
add_ending_entry(e, -1, "Elly blinked for a few seconds in shock, and then started to laugh. Just like in the old days, Reimu still treated everyone with perfect neutrality. If anyone was best suited to discovering something without biases, it was Reimu, the Shrine Maiden of Paradise.", NULL);
|
||||
add_ending_entry(e, -1, "Reimu herself had already started floating away towards the artificial horizon, and Elly watched, now completely at ease. After all, if Reimu was on the case, it would always work out right in the end. She was the unavoidable constant in a sea of variables, and using her shrine maiden intuition as her compass, there was no way that she could fail to trailblaze the way to the truth.", NULL);
|
||||
add_ending_entry(e, -1, "The only question now is what secret Reimu would, in fact, see at the end of the world.", NULL);
|
||||
add_ending_entry(e, -1, "-GOOD END-\nExtra Stage has opened up for you! Do you have what it takes to discover the hidden truth behind everything?", NULL);
|
||||
track_ending(ENDING_GOOD_3);
|
||||
}
|
||||
|
||||
static void create_ending(Ending *e) {
|
||||
memset(e, 0, sizeof(Ending));
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
// do not reorder these or change the values
|
||||
// WARNING: Reordering this will break current progress files.
|
||||
|
||||
ENDING_BAD_1,
|
||||
ENDING_BAD_2,
|
||||
ENDING_GOOD_1,
|
||||
ENDING_GOOD_2,
|
||||
|
||||
ENDING_BAD_3,
|
||||
ENDING_GOOD_3,
|
||||
NUM_ENDINGS,
|
||||
};
|
||||
|
||||
|
@ -37,5 +39,7 @@ void ending_preload(void);
|
|||
*/
|
||||
void bad_ending_marisa(Ending *e);
|
||||
void bad_ending_youmu(Ending *e);
|
||||
void bad_ending_reimu(Ending *e);
|
||||
void good_ending_marisa(Ending *e);
|
||||
void good_ending_youmu(Ending *e);
|
||||
void good_ending_reimu(Ending *e);
|
||||
|
|
|
@ -66,6 +66,7 @@ Enemy *create_enemy_p(EnemyList *enemies, complex pos, float hp, EnemyVisualRule
|
|||
|
||||
// XXX: some code relies on the insertion logic
|
||||
Enemy *e = (Enemy*)alist_insert(enemies, enemies->first, objpool_acquire(stage_object_pools.enemies));
|
||||
// Enemy *e = (Enemy*)alist_append(enemies, objpool_acquire(stage_object_pools.enemies));
|
||||
e->moving = false;
|
||||
e->dir = 0;
|
||||
|
||||
|
|
|
@ -118,7 +118,13 @@ DamageResult ent_damage(EntityInterface *ent, const DamageInfo *damage) {
|
|||
return DMG_RESULT_INAPPLICABLE;
|
||||
}
|
||||
|
||||
return ent->damage_func(ent, damage);
|
||||
DamageResult res = ent->damage_func(ent, damage);
|
||||
|
||||
if(res == DMG_RESULT_OK) {
|
||||
player_register_damage(&global.plr, ent, damage);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ent_area_damage(complex origin, float radius, const DamageInfo *damage) {
|
||||
|
|
27
src/player.c
|
@ -1062,3 +1062,30 @@ void player_preload(void) {
|
|||
"extra_bomb",
|
||||
NULL);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -168,3 +168,6 @@ bool player_is_alive(Player *plr);
|
|||
double player_get_bomb_progress(Player *plr, double *out_speed);
|
||||
|
||||
void player_preload(void);
|
||||
|
||||
// FIXME: where should this be?
|
||||
complex plrutil_homing_target(complex org, complex fallback);
|
||||
|
|
|
@ -15,13 +15,17 @@
|
|||
#include "plrmodes.h"
|
||||
#include "plrmodes/marisa.h"
|
||||
#include "plrmodes/youmu.h"
|
||||
#include "plrmodes/reimu.h"
|
||||
|
||||
static PlayerCharacter *player_characters[] = {
|
||||
&character_reimu,
|
||||
&character_marisa,
|
||||
&character_youmu,
|
||||
};
|
||||
|
||||
static PlayerMode *player_modes[] = {
|
||||
&plrmode_reimu_a,
|
||||
&plrmode_reimu_b,
|
||||
&plrmode_marisa_a,
|
||||
&plrmode_marisa_b,
|
||||
&plrmode_youmu_a,
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
#include "dialog.h"
|
||||
|
||||
typedef enum {
|
||||
/* do not reorder - screws replays */
|
||||
// WARNING: Reordering this will break current replays, and possibly even progress files.
|
||||
|
||||
PLR_CHAR_MARISA = 0,
|
||||
PLR_CHAR_YOUMU = 1,
|
||||
// PLR_CHAR_REIMU = 2,
|
||||
PLR_CHAR_REIMU = 0,
|
||||
PLR_CHAR_MARISA = 1,
|
||||
PLR_CHAR_YOUMU = 2,
|
||||
|
||||
NUM_CHARACTERS,
|
||||
} CharacterID;
|
||||
|
||||
typedef enum {
|
||||
/* do not reorder - screws replays */
|
||||
// WARNING: Reordering this will break current replays, and possibly even progress files.
|
||||
|
||||
PLR_SHOT_A,
|
||||
PLR_SHOT_B,
|
||||
|
@ -38,6 +38,9 @@ typedef enum {
|
|||
|
||||
PLR_SHOT_YOUMU_MIRROR = PLR_SHOT_A,
|
||||
PLR_SHOT_YOUMU_HAUNTING = PLR_SHOT_B,
|
||||
|
||||
PLR_SHOT_REIMU_SPIRIT = PLR_SHOT_A,
|
||||
PLR_SHOT_REIMU_DREAM = PLR_SHOT_B,
|
||||
} ShotModeID;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "global.h"
|
||||
#include "plrmodes.h"
|
||||
#include "marisa.h"
|
||||
#include "renderer/api.h"
|
||||
|
||||
PlayerCharacter character_marisa = {
|
||||
.id = PLR_CHAR_MARISA,
|
||||
|
|
|
@ -526,6 +526,10 @@ static int masterspark(Enemy *e, int t2) {
|
|||
}
|
||||
|
||||
static void marisa_laser_bombbg(Player *plr) {
|
||||
if(!player_is_bomb_active(plr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr, NULL);
|
||||
float fade = 1;
|
||||
|
||||
|
|
|
@ -234,6 +234,10 @@ static void marisa_star_bomb(Player *plr) {
|
|||
}
|
||||
|
||||
static void marisa_star_bombbg(Player *plr) {
|
||||
if(!player_is_bomb_active(plr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr, NULL);
|
||||
|
||||
ShaderProgram *s = r_shader_get("maristar_bombbg");
|
||||
|
|
|
@ -3,6 +3,9 @@ plrmodes_src = files(
|
|||
'marisa_a.c',
|
||||
'marisa_b.c',
|
||||
'marisa.c',
|
||||
'reimu_a.c',
|
||||
'reimu_b.c',
|
||||
'reimu.c',
|
||||
'youmu_a.c',
|
||||
'youmu_b.c',
|
||||
'youmu.c',
|
||||
|
|
145
src/plrmodes/reimu.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "plrmodes.h"
|
||||
#include "reimu.h"
|
||||
#include "stagedraw.h"
|
||||
|
||||
static Framebuffer *bomb_buffer;
|
||||
|
||||
PlayerCharacter character_reimu = {
|
||||
.id = PLR_CHAR_REIMU,
|
||||
.lower_name = "reimu",
|
||||
.proper_name = "Reimu",
|
||||
.full_name = "Hakurei Reimu",
|
||||
.title = "Shrine Maiden",
|
||||
.dialog_sprite_name = "dialog/reimu",
|
||||
.player_sprite_name = "player/reimu",
|
||||
.ending = {
|
||||
.good = good_ending_reimu,
|
||||
.bad = bad_ending_reimu,
|
||||
},
|
||||
};
|
||||
|
||||
double reimu_common_property(Player *plr, PlrProperty prop) {
|
||||
switch(prop) {
|
||||
case PLR_PROP_BOMB_TIME:
|
||||
return 300;
|
||||
|
||||
case PLR_PROP_COLLECT_RADIUS:
|
||||
return (plr->inputflags & INFLAG_FOCUS) ? 60 : 30;
|
||||
|
||||
case PLR_PROP_SPEED:
|
||||
// NOTE: For equivalents in Touhou units, divide these by 1.25.
|
||||
return (plr->inputflags & INFLAG_FOCUS) ? 2.5 : 5.625;
|
||||
|
||||
case PLR_PROP_POC:
|
||||
return VIEWPORT_H / 3.5;
|
||||
|
||||
case PLR_PROP_DEATHBOMB_WINDOW:
|
||||
return 12;
|
||||
}
|
||||
|
||||
UNREACHABLE;
|
||||
}
|
||||
|
||||
static int reimu_ofuda_trail(Projectile *p, int t) {
|
||||
int r = linear(p, t);
|
||||
|
||||
if(t < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
p->color.g *= 0.95;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int reimu_common_ofuda(Projectile *p, int t) {
|
||||
if(t == EVENT_DEATH) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
p->angle = carg(p->args[0]);
|
||||
|
||||
if(t == EVENT_BIRTH) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
p->pos += p->args[0];
|
||||
|
||||
PARTICLE(
|
||||
// .sprite_ptr = p->sprite,
|
||||