Compare commits

3 Commits

Author SHA1 Message Date
3b45572d38 Add game state debug log with binary ring buffer
All checks were successful
CI / build (pull_request) Successful in 32s
Deploy / deploy (push) Successful in 1m17s
Implement src/engine/debuglog module that records a comprehensive
snapshot of game state every tick into a 4 MB in-memory ring buffer.

Activated by --debug-log command-line flag. Press F12 during gameplay
to dump the ring buffer to a human-readable debug_log.txt file. The
buffer also auto-flushes every 10 seconds as a safety net.

Each tick snapshot captures: input state (held/pressed/released bitmasks),
full player state (position, velocity, health, dash, aim, timers),
camera position, physics globals, level name, and a variable-length
list of all active entity positions/velocities/health.

New files:
- src/engine/debuglog.h — API and snapshot data structures
- src/engine/debuglog.c — ring buffer, record, and dump logic

Modified files:
- include/config.h — DEBUGLOG_BUFFER_SIZE constant
- src/engine/input.h/c — input_get_snapshot() to pack input bitmasks
- src/engine/core.c — debuglog_record_tick() call after update
- src/main.c — CLI flag, init/shutdown, F12 hotkey, set_level calls

Closes #19
2026-03-16 20:33:03 +00:00
66a7b9e7e6 Fix downward dash not damaging enemies and add post-dash invincibility
Some checks failed
CI / build (pull_request) Successful in 32s
Deploy / deploy (push) Failing after 1m17s
Stomping was guarded by the invincibility check, so during a downward
dash the player could never deal stomp damage. Move the invincibility
guard to only protect against taking damage, not dealing it.

Extend dash invincibility by PLAYER_DASH_INV_GRACE (0.15s) past the
dash duration so the player is briefly protected after landing.

Closes #15
2026-03-16 20:20:05 +00:00
tas
59f76d6aa7 Update .gitea/workflows/deploy.yaml
Some checks failed
Deploy / deploy (push) Failing after 1m17s
2026-03-16 20:15:19 +00:00
4 changed files with 8 additions and 15 deletions

View File

@@ -19,14 +19,6 @@ jobs:
git config --global http.https://git.kimchi.sslVerify false
git clone --depth 1 https://${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_PASSWORD }}@git.kimchi/tas/major_tom.git .
- name: Debug registry auth
run: |
curl -s -D- http://git.kimchi/v2/ | head -15
TOKEN=$(curl -s "http://git.kimchi/v2/token?service=container_registry&scope=repository:tas/major_tom:push,pull" -u "${{
secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_PASSWORD }}" | jq -r .token)
echo "Token received: ${TOKEN:0:20}..."
curl -s -D- -H "Authorization: Bearer $TOKEN" http://git.kimchi/v2/tas/major_tom/tags/list | head -15
- name: Build and push container image
run: |
set -ex
@@ -49,9 +41,10 @@ jobs:
- name: Restart deployment on k3s
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBECONFIG }}" > ~/.kube/config
echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config
chmod 600 ~/.kube/config
kubectl delete pod -l app=${{ env.DEPLOYMENT }} -n ${{ env.NAMESPACE }}
POD_NAME=$(kubectl get pods -l app=jnr-web -n jnr-web -o jsonpath='{.items[0].metadata.name}')
echo "Deleting running pod" "$POD_NAME"
kubectl delete pod $POD_NAME -n jnr-web

View File

@@ -306,8 +306,7 @@ static void handle_collisions(EntityManager *em) {
}
/* ── Enemy contact damage to player ──── */
if (player && !(player->flags & ENTITY_INVINCIBLE) &&
entity_is_enemy(a) && !(a->flags & ENTITY_DEAD)) {
if (player && entity_is_enemy(a) && !(a->flags & ENTITY_DEAD)) {
if (physics_overlap(&a->body, &player->body)) {
/* Check if player is stomping (falling onto enemy from above) */
bool stomping = (player->body.vel.y > 0) &&
@@ -319,7 +318,7 @@ static void handle_collisions(EntityManager *em) {
damage_entity(a, 2);
if (a->flags & ENTITY_DEAD) stats_record_kill();
player->body.vel.y = -PLAYER_JUMP_FORCE * 0.7f;
} else {
} else if (!(player->flags & ENTITY_INVINCIBLE)) {
/* Charger deals extra damage and knockback while charging */
int dmg = a->damage;
if (a->type == ENT_ENEMY_CHARGER) {

View File

@@ -308,8 +308,8 @@ void player_update(Entity *self, float dt, const Tilemap *map) {
pd->dash_timer = PLAYER_DASH_DURATION;
pd->dash_dir = vec2(0.0f, 1.0f);
/* Brief invincibility during dash */
pd->inv_timer = PLAYER_DASH_DURATION;
/* Invincibility during dash + short grace period after */
pd->inv_timer = PLAYER_DASH_DURATION + PLAYER_DASH_INV_GRACE;
self->flags |= ENTITY_INVINCIBLE;
/* Jetpack burst downward */

View File

@@ -39,6 +39,7 @@
/* Invincibility after taking damage */
#define PLAYER_INV_TIME 1.5f /* seconds of invincibility */
#define PLAYER_DASH_INV_GRACE 0.15f /* extra invincibility after dash */
/* Aim direction (for shooting) */
typedef enum AimDir {