Adding patch notes from git, UI, and loading files from the main install path properly.

Also fixed:
* flying wands not pathing properly.
* Lantern particles offset
* Wand fire offset
* Water spray from flask
This commit is contained in:
Gaël committed 2026-10-22 14:18:49 +02:00
1 parent 06bb712a46
commit 9bb9797271
19 files changed
+1569 -134

No files matched your search

+10 -3
View File
@@ -45,6 +45,8 @@ layout(std430, set = 0, binding = 23) buffer Ctrl {
ivec4 hand1; // host: held wand: texel offset, w, h
vec4 hand2; // host: held wand: pivot
ivec4 burnN; // rigid_burn.comp: x the burnt pixels; y: the player's respawns, z: saved by SAVING_GRACE, w: an extra life used (the host reads and clears them)
ivec4 burnEv[256]; ivec4 reactN; ivec4 reactEv[64];
ivec4 extra; // host: x = 1: a dead player stays dead where it fell (the game over of the menus) instead of respawning
} ctrl;
#include "hit_liquid.glsl"
@@ -303,9 +305,14 @@ void main() {
if (hp <= 0.0 && (e.ex8.x & 16) != 0 && hpBeforeHit > 0.04) { hp = 0.04; atomicAdd(ctrl.burnN.z, 1); }
else if (hp <= 0.0 && (ents[id].ex8.x & 131072) != 0) { hp = min(4.0, e.aux.x > 0 ? float(e.aux.x) * 0.001 : 4.0); atomicAnd(ents[id].ex8.x, ~131072); atomicAdd(ctrl.burnN.w, 1); }
if (hp <= 0.0 && (e.ex8.x & 32768) == 0) { // respawn at the spawn point (a polymorphed body is not: the host ends the polymorph, 32768)
pos = vec2(float(e.x.z), float(e.x.w)); vel = vec2(0.0); ip = ivec2(floor(pos));
hp = e.aux.x > 0 ? float(e.aux.x) * 0.001 : 4.0;
atomicAdd(ctrl.burnN.y, 1);
if (ctrl.extra.x != 0) { // the game over (menu.h): the body stays where it fell, dead - no controls, counted once for the host
if ((flags & ST_DEAD) == 0) atomicAdd(ctrl.burnN.y, 1);
flags |= ST_DEAD; hp = 0.0; target = 0.0; want_jump = false; thrust = false;
} else {
pos = vec2(float(e.x.z), float(e.x.w)); vel = vec2(0.0); ip = ivec2(floor(pos));
hp = e.aux.x > 0 ? float(e.aux.x) * 0.001 : 4.0;
atomicAdd(ctrl.burnN.y, 1);
}
}
} else if (kind == 1 || kind == 2) { // ---- creatures ----
// the target of the creature: the player; a charmed creature (game effect CHARM) fights the nearest creature of another herd instead
+1
View File
@@ -91,6 +91,7 @@ void main() {
if (mirror) hl.y = -hl.y;
hand = root + vec2(c * hl.x - s * hl.y, s * hl.x + c * hl.y);
}
if (ctrl.hand1.w == 1) hand += vec2(mirror ? -0.5 : 0.5, 0.5); // flask entity transform, matching the host spray origin
{ // the item's recoil (00b51670): hand2.z px back along the aim, turned muzzle-up by hand0.w radians (the arm keeps the aim)
const float ia = ang + (mirror ? ctrl.hand0.w : -ctrl.hand0.w);
const float ic = cos(ia), is = sin(ia);
+11 -10
View File
@@ -62,7 +62,8 @@ void displaced_particle(uint id, FPart p) {
fparts[id].c.w = p.c.w + 1u;
return;
}
const float g = 0.1667;
const bool spray = (p.c.w & 0x200000u) != 0u;
const float g = spray ? PART_GRAV : 0.1667;
vec2 target = pos + vel;
vel.y += g * (kind == 1u ? 0.25 : 1.0);
if (kind == 1u && vel.y > 0.0) kind = 2u;
@@ -81,14 +82,14 @@ void displaced_particle(uint id, FPart p) {
uint m = cell_mat(cells[q.y * pc.gw + q.x]);
if (m != 0u) {
uint f = mflags(m);
if ((f & F_STATIC) != 0u) { dead = true; break; }
if ((f & F_LIQUID) != 0u) {
if ((f & F_STATIC) != 0u && !(spray && kind == 1u)) { dead = true; break; }
if ((f & F_LIQUID) != 0u || (spray && (f & F_STATIC) != 0u)) {
if (kind == 2u) { dead = true; break; } // mode 0 stops at liquid (and powder)
float eff = (vel.y > -0.83 || (p.c.w & 0x100000u) != 0u) ? 0.0 : dens; // mode 1: effective density 0 (an upward speed below 50 px/s, or a draw at creation) unless moving up fast; it must be lighter than the target
if (!(eff < mdensity(m)) || budget == 0u) { dead = true; break; }
budget -= 1u;
}
}
} else if (spray) kind = 2u;
} else if (spray) kind = 2u; // 00712390: leaving material ends the mode-1 penetration.
cur = nx;
}
if (!dead && int(mlen) <= 60) { // the target cell itself
@@ -98,15 +99,15 @@ void displaced_particle(uint id, FPart p) {
uint m = cell_mat(cells[q.y * pc.gw + q.x]);
if (m != 0u) {
uint f = mflags(m);
if ((f & F_STATIC) != 0u) dead = true;
else if ((f & F_LIQUID) != 0u) {
if ((f & F_STATIC) != 0u && !(spray && kind == 1u)) dead = true;
else if ((f & F_LIQUID) != 0u || (spray && (f & F_STATIC) != 0u)) {
if (kind == 2u) dead = true;
else {
float eff = (vel.y > -0.83 || (p.c.w & 0x100000u) != 0u) ? 0.0 : dens;
if (!(eff < mdensity(m)) || budget == 0u) dead = true; else budget -= 1u;
}
}
}
} else if (spray) kind = 2u;
} else if (spray) kind = 2u;
if (!dead) cur = target;
}
} else if (!dead) cur = target; // beyond the 60 probes the end point is taken as it is
@@ -116,7 +117,7 @@ void displaced_particle(uint id, FPart p) {
kind = 3u; // no place yet: it keeps trying
}
fparts[id].a = vec4(pos, vel);
fparts[id].c = uvec4(cw, kind, budget, (p.c.w & 0x100000u) | ((p.c.w & 0xFFFFFu) + 1u));
fparts[id].c = uvec4(cw, kind, budget, (p.c.w & 0x300000u) | ((p.c.w & 0xFFFFFu) + 1u));
ivec2 q = ivec2(floor(pos)) - ivec2(pc.view_x, pc.view_y);
if (q.x >= 0 && q.y >= 0 && q.x < pc.gw && q.y < pc.gh) {
vec3 col = cell_colour(cw);
+7
View File
@@ -33,6 +33,13 @@ void main() {
if (old == 0u) { ext[ci] = vec2(0.0); birth[ci] = birth_frame(); }
else if ((r.c.w & 2u) == 0u && (mflags(cell_mat(old)) & (F_GAS | F_LIQUID)) != 0u && (mflags(cell_mat(old)) & (F_STATIC | F_SAND)) == 0u && atomicCompSwap(cells[ci], old, nc) == old) { ext[ci] = vec2(0.0); birth[ci] = birth_frame(); }
}
else if (r.c.y == 7u) { // PotionSystem 00bfdd10: mode 1, density zero, 20-cell penetration budget.
const int ps = alloc_part();
if (ps < 0) return;
fparts[ps].a = r.a;
fparts[ps].b = vec4(r.b.x, 1.0, uintBitsToFloat(birth_frame()), 0.0);
fparts[ps].c = uvec4(r.c.z | (((hash3(i, uint(pc.frame), 64u) >> 16) & 0xFFu) << 16), 1u, 20u, 0x300000u);
}
else if (r.c.y == 6u) emit_displaced(r.a.xy, r.a.zw, r.c.z | (((hash3(i, uint(pc.frame), 64u) >> 16) & 0xFFu) << 16), 2u, birth_frame()); // GameCreateParticle (007b3120 -> 00716af0): a cell of the material handed to the particle system like a displaced one (AddAsParticle 007168c0): it falls and goes back into the grid, waiting for a free place
else emit_material_particle(r.a.xy, r.a.zw, r.b.x, r.b.y, r.c.x, int(r.c.z));
}
+8 -2
View File
@@ -27,7 +27,7 @@ layout(std430, set = 0, binding = 39) readonly buffer EntPrev { vec4 prevpos[];
layout(std430, set = 0, binding = 26) readonly buffer Overlay { uint overlay[]; }; // CPU-drawn HUD (ARGB, output pixels)
struct FLight { vec4 a; vec4 b; }; // x, y, radius (world cells), strength / rgb
layout(std430, set = 0, binding = 23) readonly buffer Ctrl { ivec4 inp; ivec4 inp2; ivec4 inp3; vec4 outp; vec4 outp2; vec4 view; vec4 hand0; ivec4 hand1; vec4 hand2; } ctrl;
layout(std430, set = 0, binding = 23) readonly buffer Ctrl { ivec4 inp; ivec4 inp2; ivec4 inp3; vec4 outp; vec4 outp2; vec4 view; vec4 hand0; ivec4 hand1; vec4 hand2; ivec4 burnN; ivec4 burnEv[256]; ivec4 reactN; ivec4 reactEv[64]; ivec4 extra; } ctrl; // extra.yzw: the Options' brightness, contrast, gamma x 10000 (main.cpp)
layout(std430, set = 0, binding = 38) readonly buffer FxLights { uint lcount; uint lpad[3]; FLight lights[512]; }; // lights of projectiles and explosions this frame
layout(std430, set = 0, binding = 44) readonly buffer Sky { uint sky[]; }; // src/world/sky.h
@@ -423,7 +423,7 @@ void main() {
if (p.x >= pc.ow || p.y >= pc.oh) return;
ivec2 cp = clamp(ivec2(floor(vec2(p + so + vis) / scl)), ivec2(0), ivec2(pc.gw - 1, pc.gh - 1));
vec3 rgb = unpackUnorm4x8(wcell[cp.y * pc.gw + cp.x].x).rgb; // (only the colour: the light is read for the player's pixels)
if (ctrl.inp2.y != 0 && (ents[0].st.w & 8) == 0) {
if (ctrl.inp2.y != 0 && (ents[0].st.w & 8) == 0) { // (dead: the ragdoll of 00abb7d0 is the body, main.cpp onCreatureDeath(0, true))
vec2 P = ents[0].a.xy;
const vec2 pv = prevpos[0].xy;
if (distance(pv, P) < 10.0) P = mix(pv, P, ctrl.view.z);
@@ -445,6 +445,12 @@ void main() {
rgb += vec3(0.7, 0.1, 0.0) * a * lh;
}
}
if (ctrl.extra.y != 0 || ctrl.extra.z != 0 || ctrl.extra.w != 0) { // the Options' sliders (post_final.frag: + brightness, (c - 0.5) x contrast + 0.5, pow(c, gamma), clamped; 1 + the slider for the last two)
rgb += float(ctrl.extra.y) * 1e-4;
rgb = (rgb - 0.5) * (1.0 + float(ctrl.extra.z) * 1e-4) + 0.5;
rgb = pow(max(rgb, vec3(0.0)), vec3(1.0 + float(ctrl.extra.w) * 1e-4));
rgb = clamp(rgb, 0.0, 1.0);
}
{ // the picture without the HUD for the replay recorder (the game's GIFs have no UI): clip_half.comp / main.cpp copy it
const uvec3 q0 = uvec3(clamp(rgb, 0.0, 1.0) * 255.0 + 0.5);
clipraw[p.y * pc.ow + p.x] = 0xFF000000u | (q0.r << 16) | (q0.g << 8) | q0.b;
+1 -1
View File
@@ -62,7 +62,7 @@ void main() {
ivec4 h0 = entinst[4u * id], hi = entinst[4u * id + 1u], hw = entinst[4u * id + 2u];
Ent e = ents[h0.x];
gKey = (uint(clamp(h0.w + 32768, 0, 65535)) << 16) | (65535u - (id & 65535u));
if ((e.st.w & (8 | 4096)) != 0) return; // dead, or its sprites switched off (4096: a creature, main.cpp on_components_enabled)
if ((e.st.w & (8 | 4096)) != 0) return; // dead (the host draws the ragdoll), or its sprites switched off (4096: a creature, main.cpp on_components_enabled)
if (e.st.x != 4 && (e.ex8.x & 8192) != 0) return;
{ // the hit flash: creatures, the player and physics items (a worm segment, kind 0, keeps its root slot in ex19.w)
const int fc = int(e.ex19.w + 0.5);