#version 450 #extension GL_GOOGLE_include_directive : require layout(local_size_x = 64) in; #include "common.glsl" // Projectiles shot by creatures: move in one-cell steps, die in solid cells or when they hit the player, drawn as a 3x3 blob into the entity layer. struct Ent { vec4 a, box, mv, ai; ivec4 st; vec4 hp; ivec4 x; ivec4 rg; ivec4 rg2; ivec4 aux; vec4 ex; vec4 ex2; ivec4 ex3; vec4 ex4; vec4 ex5; vec4 ex6; vec4 ex7; ivec4 ex8; vec4 ex9; vec4 ex10; vec4 ex11; vec4 ex12, ex13, ex14, ex15, ex16, ex17, ex18, ex19; }; struct Proj { vec4 a; vec4 b; vec4 c; }; // pos, vel / damage, life, gravity, colour bits / owner (0 creature, 1 player) layout(std430, set = 0, binding = 21) buffer EntLayer { uint entlayer[]; }; layout(std430, set = 0, binding = 22) buffer Ents { Ent ents[]; }; layout(std430, set = 0, binding = 25) buffer Projs { Proj projs[]; }; layout(std430, set = 0, binding = 23) readonly buffer Ctrl { ivec4 inp; ivec4 inp2; ivec4 inp3; vec4 outp; vec4 outp2; } ctrl; bool solid_at(ivec2 w) { ivec2 p = w - ivec2(pc.view_x, pc.view_y); if (p.x < 0 || p.y < 0 || p.x >= pc.gw || p.y >= pc.gh) return true; uint m = cell_mat(cells[p.y * pc.gw + p.x]); return m != 0u && (mflags(m) & (F_STATIC | F_SAND)) != 0u; } void main() { uint id = gl_GlobalInvocationID.x; if (id >= 512u) return; Proj p = projs[id]; if (p.b.y <= 0.0) return; if (pc.pass_ == 1) { // between ticks: only draw ivec2 w0 = ivec2(floor(p.a.xy)) - ivec2(pc.view_x, pc.view_y); for (int y = -1; y <= 1; ++y) for (int x = -1; x <= 1; ++x) { ivec2 q = w0 + ivec2(x, y); if (q.x >= 0 && q.y >= 0 && q.x < pc.gw && q.y < pc.gh) entlayer[q.y * pc.gw + q.x] = floatBitsToUint(p.b.w); } return; } vec2 pos = p.a.xy, vel = p.a.zw; vel.y += p.b.z; int n = max(int(ceil(length(vel))), 1); bool dead = false; vec4 pl = ents[0].a, plbox = ents[0].box; bool player_alive = (ents[0].st.w & 8) == 0 && ents[0].st.x == 3; for (int i = 0; i < n && !dead; ++i) { pos += vel / float(n); if (solid_at(ivec2(floor(pos)))) { dead = true; break; } if (p.c.x > 0.5) { // the player's bolt: hits the first living creature whose box contains it for (int k = 1; k < ctrl.inp.w; ++k) { if (ents[k].st.x == 0 || ents[k].st.x == 3 || (ents[k].st.w & 8) != 0) continue; vec2 dk = pos - ents[k].a.xy; if (dk.x >= ents[k].box.x - 1.0 && dk.x <= ents[k].box.y + 1.0 && dk.y >= ents[k].box.z - 1.0 && dk.y <= ents[k].box.w + 1.0) { atomicAdd(ents[k].x.x, int(p.b.x * ents[k].ex9.x * 1000.0)); dead = true; break; } } if (dead) break; continue; } vec2 d = pos - pl.xy; if (player_alive && d.x >= plbox.x - 1.0 && d.x <= plbox.y + 1.0 && d.y >= plbox.z - 1.0 && d.y <= plbox.w + 1.0) { atomicAdd(ents[0].x.x, int(p.b.x * ents[0].ex9.x * 1000.0)); dead = true; } } float life = dead ? 0.0 : p.b.y - 1.0; projs[id].a = vec4(pos, vel); projs[id].b = vec4(p.b.x, life, p.b.z, p.b.w); if (life > 0.0) { // draw uint col = floatBitsToUint(p.b.w); ivec2 w = ivec2(floor(pos)) - ivec2(pc.view_x, pc.view_y); for (int y = -1; y <= 1; ++y) for (int x = -1; x <= 1; ++x) { ivec2 q = w + ivec2(x, y); if (q.x >= 0 && q.y >= 0 && q.x < pc.gw && q.y < pc.gh) entlayer[q.y * pc.gw + q.x] = col; } } }