Compare commits
6 Commits
99648a71ca
...
27dc726839
| Author | SHA1 | Date | |
|---|---|---|---|
| 27dc726839 | |||
| 477c299d9f | |||
| f65e8dd9ea | |||
| 84a257f9b9 | |||
| f7c498d7ad | |||
| 7080d7fefc |
@@ -19,6 +19,14 @@ 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
|
||||
@@ -30,10 +38,6 @@ jobs:
|
||||
|
||||
CREDS="${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_PASSWORD }}"
|
||||
|
||||
echo "=== debug: Www-Authenticate header ==="
|
||||
curl -sk -I http://git.kimchi/v2/ | grep -i www-authenticate || true
|
||||
echo ""
|
||||
|
||||
echo "=== buildah push tag ==="
|
||||
buildah push --tls-verify=false --creds "$CREDS" "$IMAGE_TAG"
|
||||
|
||||
|
||||
17
AGENTS.md
17
AGENTS.md
@@ -256,6 +256,23 @@ 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
|
||||
|
||||
@@ -5,9 +5,46 @@
|
||||
#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
|
||||
* ════════════════════════════════════════════════════ */
|
||||
@@ -20,6 +57,9 @@ 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);
|
||||
@@ -48,19 +88,10 @@ static void grunt_update(Entity *self, float dt, const Tilemap *map) {
|
||||
gd->patrol_dir = -gd->patrol_dir;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
@@ -146,12 +177,14 @@ 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);
|
||||
@@ -289,6 +322,9 @@ 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);
|
||||
@@ -319,14 +355,10 @@ static void charger_update(Entity *self, float dt, const Tilemap *map) {
|
||||
}
|
||||
|
||||
/* Reverse at ledge */
|
||||
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;
|
||||
}
|
||||
if (enemy_detect_cliff(body, cd->patrol_dir,
|
||||
CHARGER_PATROL_SPEED, map)) {
|
||||
cd->patrol_dir = -cd->patrol_dir;
|
||||
body->vel.x = 0;
|
||||
}
|
||||
|
||||
/* Detect player — horizontal line-of-sight */
|
||||
@@ -510,10 +542,12 @@ 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);
|
||||
|
||||
@@ -237,11 +237,14 @@ static void damage_player(Entity *player, int damage, Entity *source) {
|
||||
ppd->inv_timer = PLAYER_INV_TIME;
|
||||
player->flags |= ENTITY_INVINCIBLE;
|
||||
|
||||
/* Knockback away from source */
|
||||
/* Knockback away from source, scaled by source speed */
|
||||
if (source) {
|
||||
float knock_dir = (player->body.pos.x < source->body.pos.x) ?
|
||||
-1.0f : 1.0f;
|
||||
player->body.vel.x = knock_dir * 150.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.y = -150.0f;
|
||||
}
|
||||
}
|
||||
@@ -317,7 +320,15 @@ static void handle_collisions(EntityManager *em) {
|
||||
if (a->flags & ENTITY_DEAD) stats_record_kill();
|
||||
player->body.vel.y = -PLAYER_JUMP_FORCE * 0.7f;
|
||||
} else {
|
||||
damage_player(player, a->damage, a);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user