1 Commits

Author SHA1 Message Date
b918ca451f Add insecure registry config and --tls-verify=false to buildah bud
The previous --tls-verify=false on login/push wasn't sufficient.
Register git.kimchi as an insecure registry and also skip TLS
verification during the image build step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:23:47 +00:00
18 changed files with 115 additions and 953 deletions

View File

@@ -21,30 +21,28 @@ jobs:
- name: Build and push container image
run: |
set -ex
mkdir -p /etc/containers
printf '[registries.insecure]\nregistries = ["git.kimchi"]\n' > /etc/containers/registries.conf
IMAGE_TAG="${{ env.IMAGE }}:sha-${GITHUB_SHA::8}"
IMAGE_LATEST="${{ env.IMAGE }}:latest"
buildah bud --tls-verify=false -f Containerfile -t "$IMAGE_TAG" -t "$IMAGE_LATEST" .
CREDS="${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_PASSWORD }}"
echo "=== buildah push tag ==="
buildah push --tls-verify=false --creds "$CREDS" "$IMAGE_TAG"
echo "=== buildah push latest ==="
buildah push --tls-verify=false --creds "$CREDS" "$IMAGE_LATEST"
buildah login --tls-verify=false "${{ env.REGISTRY }}" -u "${{ secrets.REGISTRY_USER }}" -p "${{ secrets.REGISTRY_PASSWORD }}"
buildah push --tls-verify=false "$IMAGE_TAG"
buildah push --tls-verify=false "$IMAGE_LATEST"
echo "IMAGE_TAG=$IMAGE_TAG" >> "$GITHUB_ENV"
- name: Restart deployment on k3s
- name: Deploy to k3s
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config
echo "${{ secrets.KUBECONFIG }}" > ~/.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 set image deployment/${{ env.DEPLOYMENT }} \
${{ env.DEPLOYMENT }}="${{ env.IMAGE_TAG }}" \
-n ${{ env.NAMESPACE }}
kubectl rollout status deployment/${{ env.DEPLOYMENT }} \
-n ${{ env.NAMESPACE }} --timeout=60s

View File

@@ -256,23 +256,6 @@ incremental progress.
- Draw layers: BG → entities → FG → particles → HUD
- Camera transforms world coords to screen coords
## Remote Git Server
The remote git server is a Gitea instance. Use the **`tea` CLI** (not `gh`) for all remote
operations: pull requests, issues, releases, and repository management.
```bash
tea pr create --title "..." --description "..." # Create a pull request
tea pr list # List open PRs
tea issue list # List issues
tea issue create --title "..." --description "..."
tea pr merge <number> # Merge a PR
```
Do NOT use `gh` (GitHub CLI) — it will not work with this remote.
After creating a pull request, always check out the `main` branch (`git checkout main`).
## Commit Messages
- Imperative mood, concise
- No co-authored-by or AI attribution

View File

@@ -1,51 +1,42 @@
# Level created with in-game editor
# Mars Surface - Red Dusty Plains
# ================================
# First Mars level: low gravity, wide-open terrain with wind.
# Spacecraft landing intro from moon. Charger enemies patrol
# the dusty landscape. Gun pickup midway through.
TILESET assets/tiles/mars_tileset.png
SIZE 250 23
SPAWN 3 19
SPAWN 3 18
GRAVITY 370
WIND 25
BG_COLOR 30 12 8
MUSIC assets/sounds/kaffe_og_kage.ogg
PARALLAX_STYLE 5
MUSIC assets/sounds/kaffe_og_kage.ogg
ENTITY spacecraft 1 15
ENTITY spacecraft 1 14
# Charger patrols across flat sections
ENTITY charger 40 18
ENTITY charger 75 18
ENTITY charger 120 11
ENTITY charger 165 17
ENTITY charger 120 14
ENTITY charger 165 18
ENTITY charger 200 18
# Grunts near structures
ENTITY grunt 55 18
ENTITY grunt 140 18
# Health and gun pickups
ENTITY powerup_hp 90 15
ENTITY powerup_gun 130 11
ENTITY grunt 132 18
ENTITY grunt 116 18
ENTITY grunt 28 19
ENTITY powerup_jet 177 19
ENTITY grunt 174 21
ENTITY grunt 169 21
ENTITY grunt 164 21
ENTITY grunt 159 21
ENTITY grunt 202 18
ENTITY grunt 213 13
ENTITY grunt 20 19
ENTITY powerup_fuel 24 8
ENTITY powerup_fuel 90 11
ENTITY charger 127 18
ENTITY charger 175 21
ENTITY asteroid 54 5
ENTITY asteroid 53 5
ENTITY asteroid 48 5
ENTITY powerup_gun 130 12
EXIT 246 17 2 3 assets/levels/mars02.lvl
# Tile definitions (Mars tileset)
TILEDEF 1 0 0 1
TILEDEF 2 1 0 1
TILEDEF 3 2 0 1
TILEDEF 4 0 1 2
TILEDEF 5 1 1 0
TILEDEF 6 2 1 0
LAYER collision
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
@@ -57,18 +48,15 @@ LAYER collision
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 1 1 1 1 2 1 1 1 1 2 1 1 2 1 1 1 1 1 2 1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 1 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 3 1 3 1 0 0 0 0 0 1 3 1 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 1 1 3 1 1 3 1 3 1 1 3 1 0 0 0 0 0 0 1 1 3 1 1 3 1 1 3 1 1 1 1 3 1 1 3 1 3 1 1 3 1 1 1 3 1 3 1 1 1 3 1 1 1 3 1 1 3 1 1 3 1 1 3 0 0 0 0 0 1 5 5 5 5 5 5 5 5 5 3 1 1 3 1 1 1 3 1 1 3 1 5 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 1 3 3 1 3 3 1 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 1 3 3 1 3 3 1 3 0 0 0 0 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 1 3 1 3 0 0 0 0 0 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 3 3 1 3 3 1 3 1 3 3 1 3 0 0 0 0 0 0 3 3 1 3 3 1 3 3 1 3 3 3 3 1 3 3 1 3 1 3 3 1 3 3 3 1 3 1 3 3 3 1 3 3 3 1 3 3 1 3 3 1 3 3 1 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 1 3 1 3 3 1 3 1
2 2 2 3 1 3 3 2 1 1 2 2 3 1 1 1 1 1 2 3 2 1 1 1 1 1 1 1 2 3 3 3 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2 1 3 3 2 2 3 2 2 1 3 2 2 2 1 1 1 3 1 2 2 2 2 1 3 3 3 3 3 3 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 2 1 1 1 1 0 0 0 0 0 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 2 1 1 1 1 1 0 0 0 0 0 1 2 1 1 1 1 1 2 1 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 2 1 1 1 2 1 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 1 1
1 3 1 1 3 1 1 3 1 3 1 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 3 1 1 3 1 1 3 1 0 0 0 0 1 3 1 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 3 1 3 1 0 0 0 0 0 1 3 1 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 1 1 3 1 1 3 1 3 1 1 3 1 0 0 0 0 0 0 1 1 3 1 1 3 1 1 3 1 1 1 1 3 1 1 3 1 3 1 1 3 1 1 1 3 1 3 1 1 1 3 1 1 1 3 1 1 3 1 1 3 1 1 3 0 0 0 0 0 1 3 1 1 3 1 3 1 1 1 3 1 1 3 1 1 1 3 1 1 3 1 3 1 1 1 3 1 1 3 1 1 3 1 3 1 1 1 3 1 3 1 1 3 1 1 3 1 3 1 1 3 1 1 3 1 1 1 3 1 1 3 1 1 3 1 3 1 1 1 3 1 3 1 1 1 3 1 3 1 1 1 3 1 1 3 1 1 3 1 3 1 1 3 1 3
3 1 3 3 1 3 3 1 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 1 3 3 1 3 3 1 3 0 0 0 0 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 1 3 1 3 0 0 0 0 0 3 1 3 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 3 3 1 3 3 1 3 1 3 3 1 3 0 0 0 0 0 0 3 3 1 3 3 1 3 3 1 3 3 3 3 1 3 3 1 3 1 3 3 1 3 3 3 1 3 1 3 3 3 1 3 3 3 1 3 3 1 3 3 1 3 3 1 0 0 0 0 0 3 1 3 3 1 3 1 3 3 3 1 3 3 1 3 3 3 1 3 3 1 3 1 3 3 3 1 3 3 1 3 3 1 3 1 3 3 3 1 3 1 3 3 1 3 3 1 3 1 3 3 1 3 3 1 3 3 3 1 3 3 1 3 3 1 3 1 3 3 3 1 3 1 3 3 3 1 3 1 3 3 3 1 3 3 1 3 3 1 3 1 3 3 1 3 1

View File

@@ -1,12 +1,15 @@
# Level created with in-game editor
# Moon Surface - Crater Fields
# ============================
# Second moon level: tighter platforming over deep craters.
# Spacecraft landing intro. Unarmed — pure jump-and-run with asteroids.
TILESET assets/tiles/moon_tileset.png
SIZE 200 23
SPAWN 3 18
GRAVITY 300
BG_COLOR 5 5 15
MUSIC assets/sounds/algardalgar.ogg
PARALLAX_STYLE 4
MUSIC assets/sounds/algardalgar.ogg
PLAYER_UNARMED
ENTITY spacecraft 1 14
@@ -17,22 +20,10 @@ ENTITY asteroid 105 3
ENTITY asteroid 130 0
ENTITY asteroid 155 2
ENTITY asteroid 180 1
ENTITY powerup_fuel 43 16
ENTITY powerup_fuel 46 11
ENTITY powerup_fuel 75 15
ENTITY powerup_fuel 94 12
ENTITY powerup_fuel 106 16
ENTITY powerup_fuel 130 12
ENTITY powerup_fuel 166 12
ENTITY asteroid 167 0
ENTITY asteroid 117 0
ENTITY asteroid 96 0
ENTITY asteroid 66 0
ENTITY asteroid 44 0
ENTITY asteroid 40 0
EXIT 196 17 2 3 assets/levels/moon03.lvl
# Tile definitions
TILEDEF 1 0 0 1
TILEDEF 2 1 0 1
TILEDEF 3 2 0 1
@@ -62,4 +53,3 @@ LAYER collision
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 2 2 1 1 1 2 1 2 2 1 2 2 1 0 0 0 0 0 1 2 1 1 2 1 1 1 2 0 0 0 0 0 0 0 1 1 2 2 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 1 1 1 2 2 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 2 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 2 2 1 2 2 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 2 2 1 2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 2 2 2 1 1 1 2 0 0 0 0 0 0 1 1 1 1 1 2 1 1 1 2 1 2 1
1 1 1 3 1 3 1 1 3 1 1 3 1 1 1 0 0 0 0 0 1 3 1 3 1 1 1 1 3 0 0 0 0 0 0 0 1 1 3 1 3 1 1 3 1 1 3 1 1 0 0 0 0 0 0 0 0 0 0 3 1 1 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 1 1 3 3 3 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 3 1 3 3 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 1 1 1 3 3 1 1 3 3 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 3 1 1 1 1 1 0 0 0 0 0 0 3 1 3 1 3 1 1 3 1 1 1 1 1

View File

@@ -1,12 +1,15 @@
# Level created with in-game editor
# Moon Surface - Dark Side
# ========================
# Third moon level: the hardest moon terrain with massive chasms.
# Spacecraft landing intro. Unarmed until gun powerup near exit.
TILESET assets/tiles/moon_tileset.png
SIZE 150 23
SPAWN 3 18
GRAVITY 300
BG_COLOR 5 5 15
MUSIC assets/sounds/algardalgar.ogg
PARALLAX_STYLE 4
MUSIC assets/sounds/algardalgar.ogg
PLAYER_UNARMED
ENTITY spacecraft 1 14
@@ -15,16 +18,13 @@ ENTITY asteroid 50 2
ENTITY asteroid 75 1
ENTITY asteroid 100 3
ENTITY asteroid 125 0
# Gun powerup near the exit — the player finally gets armed
ENTITY powerup_gun 130 18
ENTITY asteroid 25 1
ENTITY asteroid 60 0
ENTITY asteroid 86 0
ENTITY asteroid 98 0
ENTITY asteroid 110 0
ENTITY asteroid 120 1
EXIT 146 17 2 3 assets/levels/mars01.lvl
# Tile definitions
TILEDEF 1 0 0 1
TILEDEF 2 1 0 1
TILEDEF 3 2 0 1
@@ -40,18 +40,17 @@ LAYER collision
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 2 2 1 2 1 1 1 0 0 0 0 0 0 1 2 1 1 1 1 1 1 1 0 0 0 0 0 0 0 2 2 2 1 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 1 0 0 0 0 0 0 0 0 2 1 1 1 2 2 1 1 1 2 2 1 1 2 1 1 2 1 1 2 1
1 1 1 3 3 1 3 1 1 3 1 3 0 0 0 0 0 0 1 3 1 1 1 1 1 1 3 0 0 0 0 0 0 0 3 3 3 1 3 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 3 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 0 0 0 0 0 0 0 0 1 3 1 1 1 1 1 3 1 1 1 3 1 1 3 1 1 1 1 3 1
1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 1 1 1 2 2 1 2 1 1 1 0 0 0 0 0 0 1 2 1 1 1 1 1 1 1 0 0 0 0 0 0 0 2 2 2 1 1 2 1 2 2 0 0 0 0 0 0 0 0 0 0 1 1 1 2 1 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 2 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 1 2 1 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 2 1 1 1 1 0 0 0 0 0 0 2 1 1 1 2 2 1 1 1 2 2 1 1 2 1 1 2 1 1 2 1
1 1 1 3 3 1 3 1 1 3 1 3 0 0 0 0 0 0 1 3 1 1 1 1 1 1 3 0 0 0 0 0 0 0 3 3 3 1 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 3 3 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 3 1 3 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 3 3 1 0 0 0 0 0 0 1 3 1 1 1 1 1 3 1 1 1 3 1 1 3 1 1 1 1 3 1

View File

@@ -49,7 +49,4 @@ typedef enum TransitionStyle {
#define MAX_ASSETS 128
#define ASSET_PATH_MAX 256
/* ── Debug log ──────────────────────────────────────── */
#define DEBUGLOG_BUFFER_SIZE (4 * 1024 * 1024) /* 4 MB ring buffer */
#endif /* JNR_CONFIG_H */

View File

@@ -3,7 +3,6 @@
#include "engine/renderer.h"
#include "engine/audio.h"
#include "engine/assets.h"
#include "engine/debuglog.h"
#include <stdio.h>
#ifdef __EMSCRIPTEN__
@@ -119,7 +118,6 @@ static void engine_frame(void) {
if (s_callbacks.update) {
s_callbacks.update(DT);
}
debuglog_record_tick();
input_consume();
g_engine.tick++;
s_accumulator -= DT;

View File

@@ -1,474 +0,0 @@
#include "engine/debuglog.h"
#include "engine/core.h"
#include "engine/input.h"
#include "engine/physics.h"
#include "engine/entity.h"
#include "game/level.h"
#include "game/player.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* ═══════════════════════════════════════════════════
* File-scope state
* ═══════════════════════════════════════════════════ */
/* Ring buffer header stored at the start of the memory block. */
typedef struct RingHeader {
uint32_t magic; /* 0x44424C47 = "DBLG" */
uint32_t version;
uint32_t write_cursor; /* byte offset into data region */
uint32_t total_written; /* total snapshots written (wraps) */
uint32_t data_size; /* usable data bytes after header */
} RingHeader;
#define RING_MAGIC 0x44424C47
#define RING_VERSION 1
/* Flush the buffer to disk every this many ticks (10 s at 60 Hz). */
#define FLUSH_INTERVAL 600
static bool s_enabled;
static uint8_t *s_buffer; /* full allocation: header + data */
static RingHeader *s_header;
static uint8_t *s_data; /* start of ring data region */
static Level *s_level;
static char s_level_name[32]; /* human-readable level label */
static int s_flush_counter;
/* Path used for periodic safety-net flushes. */
static const char *s_flush_path = "debug_log_autosave.bin";
/* ═══════════════════════════════════════════════════
* Internal helpers
* ═══════════════════════════════════════════════════ */
/* Write raw bytes into the ring, wrapping at the boundary. */
static void ring_write(const void *src, uint32_t len) {
uint32_t cursor = s_header->write_cursor;
uint32_t cap = s_header->data_size;
const uint8_t *p = (const uint8_t *)src;
uint32_t first = cap - cursor;
if (first >= len) {
memcpy(s_data + cursor, p, len);
} else {
memcpy(s_data + cursor, p, first);
memcpy(s_data, p + first, len - first);
}
s_header->write_cursor = (cursor + len) % cap;
}
/* Read raw bytes from an arbitrary ring offset, wrapping. */
static void ring_read(uint32_t offset, void *dst, uint32_t len) {
uint32_t cap = s_header->data_size;
offset = offset % cap;
uint8_t *out = (uint8_t *)dst;
uint32_t first = cap - offset;
if (first >= len) {
memcpy(out, s_data + offset, len);
} else {
memcpy(out, s_data + offset, first);
memcpy(out + first, s_data, len - first);
}
}
/* Flush the entire buffer (header + data) to a binary file. */
static void flush_to_file(const char *path) {
FILE *f = fopen(path, "wb");
if (!f) {
fprintf(stderr, "Warning: debuglog flush failed — cannot open %s\n", path);
return;
}
uint32_t total = (uint32_t)sizeof(RingHeader) + s_header->data_size;
size_t written = fwrite(s_buffer, 1, total, f);
fclose(f);
if (written != total) {
fprintf(stderr, "Warning: debuglog flush incomplete (%zu / %u bytes)\n",
written, total);
}
}
/* Find the player entity in the current level, or NULL. */
static Entity *find_player(void) {
if (!s_level) return NULL;
EntityManager *em = &s_level->entities;
for (int i = 0; i < MAX_ENTITIES; i++) {
Entity *e = &em->entities[i];
if (e->active && e->type == ENT_PLAYER) return e;
}
return NULL;
}
/* Pack player-specific flags into a single byte.
* Bit layout: 0=on_ground, 1=jumping, 2=dashing, 3=invincible, 4=has_gun */
static uint8_t pack_player_flags(const Entity *player) {
uint8_t f = 0;
if (player->body.on_ground) f |= (1 << 0);
PlayerData *pd = (PlayerData *)player->data;
if (pd) {
if (pd->jumping) f |= (1 << 1);
if (pd->dash_timer > 0) f |= (1 << 2);
if (pd->inv_timer > 0) f |= (1 << 3);
if (pd->has_gun) f |= (1 << 4);
}
return f;
}
/* Pack entity-level flags into a single byte.
* Bit layout: 0=active, 1=facing_left, 2=dead, 3=invincible */
static uint8_t pack_entity_flags(const Entity *e) {
uint8_t f = 0;
if (e->active) f |= (1 << 0);
if (e->flags & ENTITY_FACING_LEFT) f |= (1 << 1);
if (e->flags & ENTITY_DEAD) f |= (1 << 2);
if (e->flags & ENTITY_INVINCIBLE) f |= (1 << 3);
return f;
}
/* Names for entity types — kept in sync with EntityType enum. */
static const char *entity_type_name(uint8_t type) {
switch ((EntityType)type) {
case ENT_NONE: return "NONE";
case ENT_PLAYER: return "PLAYER";
case ENT_ENEMY_GRUNT: return "GRUNT";
case ENT_ENEMY_FLYER: return "FLYER";
case ENT_PROJECTILE: return "PROJ";
case ENT_PICKUP: return "PICKUP";
case ENT_PARTICLE: return "PARTICLE";
case ENT_TURRET: return "TURRET";
case ENT_MOVING_PLATFORM: return "PLATFORM";
case ENT_FLAME_VENT: return "FLAME";
case ENT_FORCE_FIELD: return "FORCEFIELD";
case ENT_POWERUP: return "POWERUP";
case ENT_DRONE: return "DRONE";
case ENT_ASTEROID: return "ASTEROID";
case ENT_SPACECRAFT: return "SPACECRAFT";
case ENT_LASER_TURRET: return "LASER_TURRET";
case ENT_ENEMY_CHARGER: return "CHARGER";
case ENT_SPAWNER: return "SPAWNER";
default: return "???";
}
}
/* Names for aim directions. */
static const char *aim_dir_name(uint8_t aim) {
switch ((AimDir)aim) {
case AIM_FORWARD: return "FORWARD";
case AIM_UP: return "UP";
case AIM_DIAG_UP: return "DIAG_UP";
default: return "???";
}
}
/* Names for input actions. */
static const char *action_name(int a) {
switch ((Action)a) {
case ACTION_LEFT: return "LEFT";
case ACTION_RIGHT: return "RIGHT";
case ACTION_UP: return "UP";
case ACTION_DOWN: return "DOWN";
case ACTION_JUMP: return "JUMP";
case ACTION_SHOOT: return "SHOOT";
case ACTION_DASH: return "DASH";
case ACTION_PAUSE: return "PAUSE";
default: return "???";
}
}
/* ═══════════════════════════════════════════════════
* Public API
* ═══════════════════════════════════════════════════ */
void debuglog_init(void) {
uint32_t total = (uint32_t)sizeof(RingHeader) + DEBUGLOG_BUFFER_SIZE;
s_buffer = calloc(1, total);
if (!s_buffer) {
fprintf(stderr, "Warning: debuglog_init failed to allocate %u bytes\n", total);
return;
}
s_header = (RingHeader *)s_buffer;
s_data = s_buffer + sizeof(RingHeader);
s_header->magic = RING_MAGIC;
s_header->version = RING_VERSION;
s_header->write_cursor = 0;
s_header->total_written = 0;
s_header->data_size = DEBUGLOG_BUFFER_SIZE;
s_enabled = false;
s_level = NULL;
s_flush_counter = 0;
printf("Debug log initialized (%u KB ring buffer)\n",
DEBUGLOG_BUFFER_SIZE / 1024);
}
void debuglog_shutdown(void) {
if (!s_buffer) return;
if (s_enabled && s_header->total_written > 0) {
flush_to_file(s_flush_path);
printf("Debug log flushed to %s on shutdown (%u snapshots)\n",
s_flush_path, s_header->total_written);
}
free(s_buffer);
s_buffer = NULL;
s_header = NULL;
s_data = NULL;
s_enabled = false;
s_level = NULL;
}
void debuglog_enable(void) {
s_enabled = true;
printf("Debug log recording enabled\n");
}
bool debuglog_is_enabled(void) {
return s_enabled;
}
void debuglog_set_level(Level *lvl, const char *name) {
s_level = lvl;
if (name && name[0]) {
snprintf(s_level_name, sizeof(s_level_name), "%s", name);
} else {
s_level_name[0] = '\0';
}
}
void debuglog_record_tick(void) {
if (!s_enabled || !s_buffer) return;
/* Count active entities (skip player — recorded separately). */
uint16_t ent_count = 0;
if (s_level) {
EntityManager *em = &s_level->entities;
for (int i = 0; i < MAX_ENTITIES && ent_count < MAX_ENTITIES; i++) {
Entity *e = &em->entities[i];
if (e->active && e->type != ENT_PLAYER) ent_count++;
}
}
uint32_t frame_size = (uint32_t)sizeof(TickSnapshot)
+ (uint32_t)(ent_count * sizeof(EntitySnapshot));
/* Don't write if the frame won't fit in the ring at all. */
if (frame_size > s_header->data_size) return;
/* Build the header portion on the stack. */
TickSnapshot snap;
memset(&snap, 0, sizeof(snap));
snap.tick = g_engine.tick;
snap.frame_size = frame_size;
/* Input. */
input_get_snapshot(&snap.input);
/* Player state. */
Entity *player = find_player();
if (player) {
snap.player_x = player->body.pos.x;
snap.player_y = player->body.pos.y;
snap.player_vx = player->body.vel.x;
snap.player_vy = player->body.vel.y;
snap.player_health = (int8_t)player->health;
snap.player_flags = pack_player_flags(player);
PlayerData *pd = (PlayerData *)player->data;
if (pd) {
snap.player_dash_timer = pd->dash_timer;
snap.player_dash_charges = (int8_t)pd->dash_charges;
snap.player_inv_timer = pd->inv_timer;
snap.player_coyote = pd->coyote_timer;
snap.player_aim_dir = (uint8_t)pd->aim_dir;
}
}
/* Camera. */
if (s_level) {
snap.cam_x = s_level->camera.pos.x;
snap.cam_y = s_level->camera.pos.y;
}
/* Physics globals. */
snap.gravity = physics_get_gravity();
snap.wind = physics_get_wind();
/* Level name (truncated to 31 chars + NUL). */
if (s_level_name[0]) {
snprintf(snap.level_name, sizeof(snap.level_name), "%s", s_level_name);
}
snap.entity_count = ent_count;
/* Write header into ring. */
ring_write(&snap, sizeof(TickSnapshot));
/* Write entity snapshots. */
if (s_level && ent_count > 0) {
EntityManager *em = &s_level->entities;
for (int i = 0; i < MAX_ENTITIES; i++) {
Entity *e = &em->entities[i];
if (!e->active || e->type == ENT_PLAYER) continue;
EntitySnapshot es;
es.type = (uint8_t)e->type;
es.flags = pack_entity_flags(e);
es.health = (int16_t)e->health;
es.pos_x = e->body.pos.x;
es.pos_y = e->body.pos.y;
es.vel_x = e->body.vel.x;
es.vel_y = e->body.vel.y;
ring_write(&es, sizeof(EntitySnapshot));
}
}
s_header->total_written++;
/* Periodic safety-net flush. */
s_flush_counter++;
if (s_flush_counter >= FLUSH_INTERVAL) {
s_flush_counter = 0;
flush_to_file(s_flush_path);
}
}
void debuglog_dump(const char *path) {
if (!s_buffer || s_header->total_written == 0) {
printf("Debug log: nothing to dump (0 snapshots recorded)\n");
return;
}
FILE *f = fopen(path, "w");
if (!f) {
fprintf(stderr, "Error: cannot open %s for writing\n", path);
return;
}
fprintf(f, "=== Debug Log Dump ===\n");
fprintf(f, "Total snapshots written: %u\n\n", s_header->total_written);
/* Walk backwards from write_cursor to find snapshots.
* We read forward through the ring, starting from the oldest data. */
/* To find the oldest snapshot: if the buffer has wrapped, oldest
* starts at write_cursor. Otherwise it starts at 0. */
uint32_t cap = s_header->data_size;
uint32_t total_data_bytes;
uint32_t read_pos;
/* Estimate how much data we've written total. If total_written
* snapshots have been recorded and we assume average frame size
* is frame_size, the buffer may have wrapped. We use a simpler
* approach: scan forward from the oldest point. */
if (s_header->total_written * sizeof(TickSnapshot) >= cap) {
/* Buffer has likely wrapped. Start reading at write_cursor
* (which is where the oldest data begins). */
read_pos = s_header->write_cursor;
total_data_bytes = cap;
} else {
read_pos = 0;
total_data_bytes = s_header->write_cursor;
}
uint32_t bytes_read = 0;
uint32_t snapshots_dumped = 0;
uint32_t first_tick = 0;
uint32_t last_tick = 0;
while (bytes_read + sizeof(TickSnapshot) <= total_data_bytes) {
TickSnapshot snap;
ring_read(read_pos, &snap, sizeof(TickSnapshot));
/* Sanity check. */
if (snap.frame_size < sizeof(TickSnapshot) ||
snap.frame_size > cap) {
break;
}
if (bytes_read + snap.frame_size > total_data_bytes) {
break;
}
if (snapshots_dumped == 0) first_tick = snap.tick;
last_tick = snap.tick;
fprintf(f, "--- Tick %u ---\n", snap.tick);
/* Input. */
fprintf(f, "Input:");
for (int a = 0; a < ACTION_COUNT && a < 8; a++) {
if (snap.input.held & (1 << a)) {
fprintf(f, " [%s]", action_name(a));
}
if (snap.input.pressed & (1 << a)) {
fprintf(f, " [%s_pressed]", action_name(a));
}
if (snap.input.released & (1 << a)) {
fprintf(f, " [%s_released]", action_name(a));
}
}
fprintf(f, "\n");
/* Player. */
fprintf(f, "Player: pos=(%.1f, %.1f) vel=(%.1f, %.1f) hp=%d",
snap.player_x, snap.player_y,
snap.player_vx, snap.player_vy,
snap.player_health);
fprintf(f, " on_ground=%d", (snap.player_flags >> 0) & 1);
fprintf(f, " jumping=%d", (snap.player_flags >> 1) & 1);
fprintf(f, " dashing=%d", (snap.player_flags >> 2) & 1);
fprintf(f, " inv=%d", (snap.player_flags >> 3) & 1);
fprintf(f, " has_gun=%d", (snap.player_flags >> 4) & 1);
fprintf(f, " aim=%s", aim_dir_name(snap.player_aim_dir));
fprintf(f, " dash_charges=%d dash_timer=%.2f inv_timer=%.2f coyote=%.3f\n",
snap.player_dash_charges, snap.player_dash_timer,
snap.player_inv_timer, snap.player_coyote);
/* Camera + physics. */
fprintf(f, "Camera: (%.1f, %.1f)\n", snap.cam_x, snap.cam_y);
fprintf(f, "Physics: gravity=%.1f wind=%.1f\n",
snap.gravity, snap.wind);
if (snap.level_name[0]) {
fprintf(f, "Level: %s\n", snap.level_name);
}
/* Entities. */
fprintf(f, "Entities (%u active):\n", snap.entity_count);
uint32_t ent_offset = (read_pos + sizeof(TickSnapshot)) % cap;
uint16_t count = snap.entity_count;
if (count > MAX_ENTITIES) count = MAX_ENTITIES;
for (uint16_t i = 0; i < count; i++) {
EntitySnapshot es;
ring_read(ent_offset, &es, sizeof(EntitySnapshot));
ent_offset = (ent_offset + sizeof(EntitySnapshot)) % cap;
fprintf(f, " [%u] %-12s pos=(%.0f, %.0f) vel=(%.0f, %.0f) hp=%d\n",
i, entity_type_name(es.type),
es.pos_x, es.pos_y,
es.vel_x, es.vel_y,
es.health);
}
fprintf(f, "\n");
read_pos = (read_pos + snap.frame_size) % cap;
bytes_read += snap.frame_size;
snapshots_dumped++;
}
/* Write summary at the top. */
if (snapshots_dumped > 0) {
float seconds = (float)(last_tick - first_tick) / TICK_RATE;
fprintf(f, "=== Summary: ticks %u to %u (%u snapshots, %.1f seconds) ===\n",
first_tick, last_tick, snapshots_dumped, seconds);
}
fclose(f);
printf("Debug log dumped to %s (%u snapshots)\n", path, snapshots_dumped);
}

View File

@@ -1,91 +0,0 @@
#ifndef JNR_DEBUGLOG_H
#define JNR_DEBUGLOG_H
#include <stdbool.h>
#include <stdint.h>
#include "config.h"
/* Forward declaration — game layer type, registered via pointer. */
typedef struct Level Level;
/* ═══════════════════════════════════════════════════
* Snapshot data structures
* ═══════════════════════════════════════════════════ */
/* Packed input snapshot — 3 bytes (ACTION_COUNT actions × 3 states). */
typedef struct InputSnapshot {
uint8_t held; /* bitmask of ACTION_* held this tick */
uint8_t pressed; /* bitmask of ACTION_* pressed this tick */
uint8_t released; /* bitmask of ACTION_* released this tick */
} InputSnapshot;
/* Per-entity summary — 20 bytes each. */
typedef struct EntitySnapshot {
uint8_t type; /* EntityType */
uint8_t flags; /* active, facing, dead, invincible */
int16_t health;
float pos_x, pos_y;
float vel_x, vel_y;
} EntitySnapshot;
/* Full tick snapshot — fixed-size header + variable entity list.
* Written sequentially into the ring buffer; frame_size stores
* the total byte count so the reader can skip forward. */
typedef struct TickSnapshot {
uint32_t tick; /* g_engine.tick */
uint32_t frame_size; /* total bytes of this record */
/* Input */
InputSnapshot input; /* 3 bytes */
uint8_t _pad0; /* align to 4 bytes */
/* Player state (expanded) */
float player_x, player_y;
float player_vx, player_vy;
int8_t player_health;
uint8_t player_flags; /* on_ground, jumping, dashing, inv, has_gun */
uint8_t player_aim_dir;
int8_t player_dash_charges;
float player_dash_timer;
float player_inv_timer;
float player_coyote;
/* Camera */
float cam_x, cam_y;
/* Physics globals */
float gravity;
float wind;
/* Level info */
char level_name[32]; /* truncated level path/tag */
/* Entity summary */
uint16_t entity_count; /* number of active entities */
uint16_t _pad1; /* alignment padding */
/* EntitySnapshot entities[] follows immediately in the buffer. */
} TickSnapshot;
/* ═══════════════════════════════════════════════════
* Public API
* ═══════════════════════════════════════════════════ */
/* Allocate ring buffer. Safe to call even if logging stays disabled. */
void debuglog_init(void);
/* Final flush + free. */
void debuglog_shutdown(void);
/* Turn on recording. */
void debuglog_enable(void);
/* Query state. */
bool debuglog_is_enabled(void);
/* Register the active Level pointer so the debuglog can read game state.
* Pass NULL before freeing a level.
* name is an optional label (e.g. file path); NULL or "" to clear. */
void debuglog_set_level(Level *lvl, const char *name);
/* Called once per tick from engine_frame, after update, before consume.
* Captures input + game state into the ring buffer. */
void debuglog_record_tick(void);
/* Dump the ring buffer contents to a human-readable text file. */
void debuglog_dump(const char *path);
#endif /* JNR_DEBUGLOG_H */

View File

@@ -1,5 +1,4 @@
#include "engine/input.h"
#include "engine/debuglog.h"
#include <string.h>
static bool s_current[ACTION_COUNT];
@@ -197,19 +196,6 @@ bool input_key_held(SDL_Scancode key) {
return s_key_state && s_key_state[key];
}
/* ── Debug log snapshot ───────────────────────────── */
void input_get_snapshot(InputSnapshot *out) {
out->held = 0;
out->pressed = 0;
out->released = 0;
for (int i = 0; i < ACTION_COUNT && i < 8; i++) {
if (s_current[i]) out->held |= (uint8_t)(1 << i);
if (s_latched_pressed[i]) out->pressed |= (uint8_t)(1 << i);
if (s_latched_released[i]) out->released |= (uint8_t)(1 << i);
}
}
void input_shutdown(void) {
/* Nothing to clean up */
}

View File

@@ -50,10 +50,4 @@ int input_mouse_scroll(void);
bool input_key_pressed(SDL_Scancode key);
bool input_key_held(SDL_Scancode key);
/* Pack current input state into a compact bitmask snapshot.
* Used by the debug log to record per-tick input without
* exposing internal arrays. */
typedef struct InputSnapshot InputSnapshot; /* defined in debuglog.h */
void input_get_snapshot(InputSnapshot *out);
#endif /* JNR_INPUT_H */

View File

@@ -530,124 +530,6 @@ void particle_emit_wall_slide_dust(Vec2 pos, int wall_dir) {
particle_emit(&dust);
}
void particle_emit_hit_sparks(Vec2 pos) {
/* Bright orange-white sparks — fast, short-lived, spray outward */
ParticleBurst sparks = {
.origin = pos,
.count = 8,
.speed_min = 60.0f,
.speed_max = 180.0f,
.life_min = 0.08f,
.life_max = 0.2f,
.size_min = 1.0f,
.size_max = 2.0f,
.spread = (float)M_PI,
.direction = 0,
.drag = 3.0f,
.gravity_scale = 0.4f,
.color = {255, 200, 100, 255}, /* orange-white */
.color_vary = true,
};
particle_emit(&sparks);
/* Brief white flash at impact point */
ParticleBurst flash = {
.origin = pos,
.count = 3,
.speed_min = 5.0f,
.speed_max = 15.0f,
.life_min = 0.03f,
.life_max = 0.06f,
.size_min = 2.0f,
.size_max = 3.5f,
.spread = (float)M_PI,
.direction = 0,
.drag = 8.0f,
.gravity_scale = 0.0f,
.color = {255, 255, 230, 255}, /* bright white */
.color_vary = false,
};
particle_emit(&flash);
}
void particle_emit_metal_explosion(Vec2 pos) {
/* Metal shrapnel — fast grey/silver chunks flying outward */
ParticleBurst shrapnel = {
.origin = pos,
.count = 16,
.speed_min = 60.0f,
.speed_max = 200.0f,
.life_min = 0.2f,
.life_max = 0.6f,
.size_min = 1.5f,
.size_max = 3.5f,
.spread = (float)M_PI,
.direction = 0,
.drag = 2.0f,
.gravity_scale = 0.5f,
.color = {180, 180, 190, 255}, /* silver-grey */
.color_vary = true,
};
particle_emit(&shrapnel);
/* Hot orange sparks — electrical/mechanical innards */
ParticleBurst sparks = {
.origin = pos,
.count = 10,
.speed_min = 40.0f,
.speed_max = 150.0f,
.life_min = 0.15f,
.life_max = 0.35f,
.size_min = 1.0f,
.size_max = 2.5f,
.spread = (float)M_PI,
.direction = 0,
.drag = 2.5f,
.gravity_scale = 0.3f,
.color = {255, 160, 40, 255}, /* hot orange */
.color_vary = true,
};
particle_emit(&sparks);
/* Bright white flash at center — brief pop */
ParticleBurst flash = {
.origin = pos,
.count = 5,
.speed_min = 5.0f,
.speed_max = 20.0f,
.life_min = 0.04f,
.life_max = 0.08f,
.size_min = 3.0f,
.size_max = 5.0f,
.spread = (float)M_PI,
.direction = 0,
.drag = 8.0f,
.gravity_scale = 0.0f,
.color = {255, 240, 200, 255}, /* bright flash */
.color_vary = false,
};
particle_emit(&flash);
/* Smoke cloud — slower, lingers */
ParticleBurst smoke = {
.origin = pos,
.count = 8,
.speed_min = 15.0f,
.speed_max = 50.0f,
.life_min = 0.3f,
.life_max = 0.7f,
.size_min = 2.5f,
.size_max = 4.5f,
.spread = (float)M_PI,
.direction = 0,
.drag = 3.5f,
.gravity_scale = -0.1f, /* floats up */
.color = {120, 120, 130, 180}, /* dark smoke */
.color_vary = true,
};
particle_emit(&smoke);
}
/* Spawn a single dust mote with the given visual properties. */
static void spawn_dust_mote(Vec2 pos, Vec2 vel,
float life_min, float life_max,

View File

@@ -89,12 +89,6 @@ void particle_emit_muzzle_flash(Vec2 pos, Vec2 shoot_dir);
/* Wall slide dust (small puffs while scraping against a wall) */
void particle_emit_wall_slide_dust(Vec2 pos, int wall_dir);
/* Metal hit sparks (turret/machine takes non-lethal damage) */
void particle_emit_hit_sparks(Vec2 pos);
/* Metal explosion (turret/machine death — shrapnel + flash) */
void particle_emit_metal_explosion(Vec2 pos);
/* Ambient atmosphere dust (call each frame for Mars Surface levels).
* Spawns subtle dust motes around the camera viewport that drift with wind.
* cam_pos = camera top-left world position, vp = viewport size in pixels. */

View File

@@ -5,46 +5,9 @@
#include "engine/renderer.h"
#include "engine/particle.h"
#include "engine/audio.h"
#include "config.h"
#include <stdlib.h>
#include <math.h>
/* ── Shared helpers ───────────────────────────────── */
/* Kill enemy if it fell past the bottom of the level. */
static bool enemy_check_level_bottom(Entity *self, const Tilemap *map,
EntityManager *em) {
float level_bottom = (float)(map->height * TILE_SIZE);
if (self->body.pos.y > level_bottom) {
self->flags |= ENTITY_DEAD;
self->health = 0;
entity_destroy(em, self);
return true;
}
return false;
}
/* Check for cliff ahead of a ground enemy. Returns true if cliff detected.
* Uses a wider lookahead that scales with speed for fast-moving enemies. */
static bool enemy_detect_cliff(const Body *body, float patrol_dir,
float speed, const Tilemap *map) {
if (!body->on_ground) return false;
/* Scale lookahead with speed: at least 4px, up to speed/10 */
float lookahead = speed * 0.1f;
if (lookahead < 4.0f) lookahead = 4.0f;
float check_x = (patrol_dir > 0) ?
body->pos.x + body->size.x + lookahead :
body->pos.x - lookahead;
float check_y = body->pos.y + body->size.y + 4.0f;
int tx = world_to_tile(check_x);
int ty = world_to_tile(check_y);
return !tilemap_is_solid(map, tx, ty);
}
/* ════════════════════════════════════════════════════
* GRUNT - ground patrol enemy
* ════════════════════════════════════════════════════ */
@@ -57,9 +20,6 @@ static void grunt_update(Entity *self, float dt, const Tilemap *map) {
Body *body = &self->body;
/* Kill if fallen off bottom of level */
if (enemy_check_level_bottom(self, map, s_grunt_em)) return;
/* Death sequence */
if (self->flags & ENTITY_DEAD) {
animation_set(&self->anim, &anim_grunt_death);
@@ -88,10 +48,19 @@ static void grunt_update(Entity *self, float dt, const Tilemap *map) {
gd->patrol_dir = -gd->patrol_dir;
}
/* Turn around at ledge */
if (enemy_detect_cliff(body, gd->patrol_dir, GRUNT_SPEED, map)) {
gd->patrol_dir = -gd->patrol_dir;
body->vel.x = 0;
/* Turn around at ledge: check if there's ground ahead */
if (body->on_ground) {
float check_x = (gd->patrol_dir > 0) ?
body->pos.x + body->size.x + 2.0f :
body->pos.x - 2.0f;
float check_y = body->pos.y + body->size.y + 4.0f;
int tx = world_to_tile(check_x);
int ty = world_to_tile(check_y);
if (!tilemap_is_solid(map, tx, ty)) {
gd->patrol_dir = -gd->patrol_dir;
}
}
/* Animation */
@@ -177,14 +146,12 @@ static Entity *find_player(EntityManager *em) {
}
static void flyer_update(Entity *self, float dt, const Tilemap *map) {
(void)map; /* flyers don't collide with tiles */
FlyerData *fd = (FlyerData *)self->data;
if (!fd) return;
Body *body = &self->body;
/* Kill if fallen off bottom of level */
if (enemy_check_level_bottom(self, map, s_flyer_em)) return;
/* Death sequence */
if (self->flags & ENTITY_DEAD) {
animation_set(&self->anim, &anim_flyer_death);
@@ -322,9 +289,6 @@ static void charger_update(Entity *self, float dt, const Tilemap *map) {
Body *body = &self->body;
/* Kill if fallen off bottom of level */
if (enemy_check_level_bottom(self, map, s_charger_em)) return;
/* Death sequence */
if (self->flags & ENTITY_DEAD) {
animation_set(&self->anim, &anim_charger_death);
@@ -355,10 +319,14 @@ static void charger_update(Entity *self, float dt, const Tilemap *map) {
}
/* Reverse at ledge */
if (enemy_detect_cliff(body, cd->patrol_dir,
CHARGER_PATROL_SPEED, map)) {
cd->patrol_dir = -cd->patrol_dir;
body->vel.x = 0;
if (body->on_ground) {
float cx = (cd->patrol_dir > 0) ?
body->pos.x + body->size.x + 2.0f :
body->pos.x - 2.0f;
float cy = body->pos.y + body->size.y + 4.0f;
if (!tilemap_is_solid(map, world_to_tile(cx), world_to_tile(cy))) {
cd->patrol_dir = -cd->patrol_dir;
}
}
/* Detect player — horizontal line-of-sight */
@@ -542,12 +510,10 @@ static int count_alive_grunts(EntityManager *em) {
}
static void spawner_update(Entity *self, float dt, const Tilemap *map) {
(void)map;
SpawnerData *sd = (SpawnerData *)self->data;
if (!sd) return;
/* Kill if fallen off bottom of level */
if (enemy_check_level_bottom(self, map, s_spawner_em)) return;
/* Death sequence */
if (self->flags & ENTITY_DEAD) {
animation_set(&self->anim, &anim_spawner_death);

View File

@@ -177,45 +177,36 @@ static Camera *s_active_camera = NULL;
static void damage_entity(Entity *target, int damage) {
target->health -= damage;
Vec2 center = vec2(
target->body.pos.x + target->body.size.x * 0.5f,
target->body.pos.y + target->body.size.y * 0.5f
);
if (target->health <= 0) {
target->flags |= ENTITY_DEAD;
/* Death particles — turrets get a metal explosion, others a puff */
if (target->type == ENT_TURRET || target->type == ENT_LASER_TURRET) {
particle_emit_metal_explosion(center);
/* Death particles — centered on entity */
Vec2 center = vec2(
target->body.pos.x + target->body.size.x * 0.5f,
target->body.pos.y + target->body.size.y * 0.5f
);
SDL_Color death_color;
if (target->type == ENT_ENEMY_GRUNT) {
death_color = (SDL_Color){200, 60, 60, 255}; /* red debris */
} else if (target->type == ENT_ENEMY_FLYER) {
death_color = (SDL_Color){140, 80, 200, 255}; /* purple puff */
} else if (target->type == ENT_TURRET || target->type == ENT_LASER_TURRET) {
death_color = (SDL_Color){160, 160, 160, 255}; /* metal scraps */
} else if (target->type == ENT_ENEMY_CHARGER) {
death_color = (SDL_Color){220, 140, 40, 255}; /* orange spark */
} else if (target->type == ENT_SPAWNER) {
death_color = (SDL_Color){180, 60, 180, 255}; /* purple burst */
} else {
SDL_Color death_color;
if (target->type == ENT_ENEMY_GRUNT) {
death_color = (SDL_Color){200, 60, 60, 255};
} else if (target->type == ENT_ENEMY_FLYER) {
death_color = (SDL_Color){140, 80, 200, 255};
} else if (target->type == ENT_ENEMY_CHARGER) {
death_color = (SDL_Color){220, 140, 40, 255};
} else if (target->type == ENT_SPAWNER) {
death_color = (SDL_Color){180, 60, 180, 255};
} else {
death_color = (SDL_Color){200, 200, 200, 255};
}
particle_emit_death_puff(center, death_color);
death_color = (SDL_Color){200, 200, 200, 255}; /* grey */
}
particle_emit_death_puff(center, death_color);
/* Screen shake on kill — stronger for turret explosions */
/* Screen shake on kill */
if (s_active_camera) {
float intensity = (target->type == ENT_TURRET ||
target->type == ENT_LASER_TURRET) ? 3.5f : 2.0f;
camera_shake(s_active_camera, intensity, 0.15f);
camera_shake(s_active_camera, 2.0f, 0.15f);
}
audio_play_sound_at(s_sfx_enemy_death, 80, center, 0);
} else if (target->type == ENT_TURRET || target->type == ENT_LASER_TURRET) {
/* Hit marker sparks on non-lethal turret damage */
particle_emit_hit_sparks(center);
}
}
@@ -237,14 +228,11 @@ static void damage_player(Entity *player, int damage, Entity *source) {
ppd->inv_timer = PLAYER_INV_TIME;
player->flags |= ENTITY_INVINCIBLE;
/* Knockback away from source, scaled by source speed */
/* Knockback away from source */
if (source) {
float knock_dir = (player->body.pos.x < source->body.pos.x) ?
-1.0f : 1.0f;
float src_speed = fabsf(source->body.vel.x);
float knock_str = 150.0f;
if (src_speed > knock_str) knock_str = src_speed;
player->body.vel.x = knock_dir * knock_str;
player->body.vel.x = knock_dir * 150.0f;
player->body.vel.y = -150.0f;
}
}
@@ -306,7 +294,8 @@ static void handle_collisions(EntityManager *em) {
}
/* ── Enemy contact damage to player ──── */
if (player && entity_is_enemy(a) && !(a->flags & ENTITY_DEAD)) {
if (player && !(player->flags & ENTITY_INVINCIBLE) &&
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) &&
@@ -318,16 +307,8 @@ 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 if (!(player->flags & ENTITY_INVINCIBLE)) {
/* Charger deals extra damage and knockback while charging */
int dmg = a->damage;
if (a->type == ENT_ENEMY_CHARGER) {
ChargerData *cd = (ChargerData *)a->data;
if (cd && cd->state == CHARGER_CHARGE) {
dmg = 2;
}
}
damage_player(player, dmg, a);
} else {
damage_player(player, a->damage, a);
}
}
}

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);
/* Invincibility during dash + short grace period after */
pd->inv_timer = PLAYER_DASH_DURATION + PLAYER_DASH_INV_GRACE;
/* Brief invincibility during dash */
pd->inv_timer = PLAYER_DASH_DURATION;
self->flags |= ENTITY_INVINCIBLE;
/* Jetpack burst downward */

View File

@@ -39,7 +39,6 @@
/* 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 {

View File

@@ -1,7 +1,6 @@
#include "engine/core.h"
#include "engine/input.h"
#include "engine/font.h"
#include "engine/debuglog.h"
#include "game/level.h"
#include "game/levelgen.h"
#include "game/editor.h"
@@ -35,7 +34,6 @@ static GameMode s_mode = MODE_PLAY;
static bool s_use_procgen = false;
static bool s_dump_lvl = false;
static bool s_use_editor = false;
static bool s_use_debuglog = false;
static uint32_t s_gen_seed = 0;
static char s_edit_path[256] = {0};
static char s_level_path[ASSET_PATH_MAX] = {0}; /* path of active play-mode level */
@@ -96,7 +94,6 @@ static const char *theme_name(LevelTheme t) {
static bool load_level_file(const char *path) {
if (!level_load(&s_level, path)) return false;
snprintf(s_level_path, sizeof(s_level_path), "%s", path);
debuglog_set_level(&s_level, path);
return true;
}
@@ -195,7 +192,6 @@ static void load_generated_level(void) {
g_engine.running = false;
}
s_level_path[0] = '\0'; /* generated levels have no file path */
debuglog_set_level(&s_level, "generated");
}
static void load_station_level(void) {
@@ -221,7 +217,6 @@ static void load_station_level(void) {
g_engine.running = false;
}
s_level_path[0] = '\0'; /* generated levels have no file path */
debuglog_set_level(&s_level, "generated:station");
}
static void load_mars_base_level(void) {
@@ -253,7 +248,6 @@ static void load_mars_base_level(void) {
g_engine.running = false;
}
s_level_path[0] = '\0';
debuglog_set_level(&s_level, "generated:mars_base");
}
/* ── Analytics session helpers ── */
@@ -274,7 +268,6 @@ static void end_session(const char *reason) {
/* ── Switch to editor mode ── */
static void enter_editor(void) {
if (s_mode == MODE_PLAY) {
debuglog_set_level(NULL, NULL);
level_free(&s_level);
}
s_mode = MODE_EDITOR;
@@ -314,7 +307,6 @@ static void enter_test_play(void) {
/* ── Return from test play to editor ── */
static void return_to_editor(void) {
debuglog_set_level(NULL, NULL);
level_free(&s_level);
s_mode = MODE_EDITOR;
s_testing_from_editor = false;
@@ -323,7 +315,6 @@ static void return_to_editor(void) {
/* ── Restart current level (file-based or generated) ── */
static void restart_level(void) {
debuglog_set_level(NULL, NULL);
level_free(&s_level);
if (s_level_path[0]) {
if (!load_level_file(s_level_path)) {
@@ -338,7 +329,6 @@ static void restart_level(void) {
/* ── Level load dispatch — loads the next level based on target string ── */
static void dispatch_level_load(const char *target) {
debuglog_set_level(NULL, NULL);
if (target[0] == '\0') {
/* Empty target = victory / end of game. */
printf("Level complete! (no next level)\n");
@@ -467,7 +457,6 @@ static void game_update(float dt) {
/* Tear down whatever mode we are in. */
if (s_mode == MODE_PLAY || s_mode == MODE_PAUSED
|| s_mode == MODE_TRANSITION) {
debuglog_set_level(NULL, NULL);
transition_reset(&s_transition);
level_free(&s_level);
}
@@ -535,11 +524,6 @@ static void game_update(float dt) {
/* ── Play mode ── */
/* F12: dump debug log to text file. */
if (input_key_pressed(SDL_SCANCODE_F12) && debuglog_is_enabled()) {
debuglog_dump("debug_log.txt");
}
/* Pause on escape (return to editor during test play) */
if (input_pressed(ACTION_PAUSE)) {
if (s_testing_from_editor) {
@@ -555,7 +539,6 @@ static void game_update(float dt) {
if (!s_testing_from_editor && input_key_pressed(SDL_SCANCODE_E)) {
/* Load the current level file into the editor if available */
snprintf(s_edit_path, sizeof(s_edit_path), "%s", s_level_path);
debuglog_set_level(NULL, NULL);
level_free(&s_level);
enter_editor();
return;
@@ -567,7 +550,6 @@ static void game_update(float dt) {
if (r_pressed && !r_was_pressed) {
printf("\n=== Regenerating level ===\n");
end_session("quit");
debuglog_set_level(NULL, NULL);
level_free(&s_level);
s_gen_seed = (uint32_t)time(NULL);
s_use_procgen = true;
@@ -665,7 +647,6 @@ static void game_render(float interpolation) {
static void game_shutdown(void) {
end_session("quit");
debuglog_set_level(NULL, NULL);
/* Always free both — editor may have been initialized even if we're
* currently in play mode (e.g. shutdown during test play). editor_free
@@ -694,8 +675,6 @@ int main(int argc, char *argv[]) {
if (i + 1 < argc) {
s_gen_seed = (uint32_t)atoi(argv[++i]);
}
} else if (strcmp(argv[i], "--debug-log") == 0) {
s_use_debuglog = true;
} else if (strcmp(argv[i], "--edit") == 0 || strcmp(argv[i], "-e") == 0) {
s_use_editor = true;
/* Optional: next arg is a file path */
@@ -708,7 +687,6 @@ int main(int argc, char *argv[]) {
printf(" --dump, -d Dump generated level to assets/levels/generated.lvl\n");
printf(" --seed N, -s N Set RNG seed for generation\n");
printf(" --edit [file], -e [file] Open level editor (optionally load a .lvl file)\n");
printf(" --debug-log Record game state every tick (F12 to dump)\n");
printf("\nIn-game:\n");
printf(" R Regenerate level with new random seed\n");
printf(" E Open level editor\n");
@@ -761,11 +739,6 @@ int main(int argc, char *argv[]) {
return 1;
}
debuglog_init();
if (s_use_debuglog) {
debuglog_enable();
}
engine_set_callbacks((GameCallbacks){
.init = game_init,
.update = game_update,
@@ -774,7 +747,6 @@ int main(int argc, char *argv[]) {
});
engine_run();
debuglog_shutdown();
engine_shutdown();
return 0;