diff --git a/engine-c/openkknd b/engine-c/openkknd index 4fa9fdf..041df9f 100755 Binary files a/engine-c/openkknd and b/engine-c/openkknd differ diff --git a/engine-c/src/projectiles.c b/engine-c/src/projectiles.c index 53be2e0..fc19388 100644 --- a/engine-c/src/projectiles.c +++ b/engine-c/src/projectiles.c @@ -57,8 +57,12 @@ void bullet_update(Game *g, float dt) { Building *t = bld_by_id(g, b->target_bld); if (t) bld_apply_damage(g, t, b->damage); } - particle_burst(g, b->tx, b->ty, 4, - (b->kind==2)?2:1, 255, 200, 80); + /* denser impact: fire/laser core + smoke ring */ + int hit_kind = (b->kind == 2) ? 2 : 1; + particle_burst(g, b->tx, b->ty, 7, hit_kind, 255, 200, 80); + particle_burst(g, b->tx, b->ty, 4, 0, 90, 80, 60); + if (b->kind == 1 || b->kind == 3) + particle_burst(g, b->tx, b->ty, 3, 3, 255, 140, 40); /* swap-remove */ g->bullets[i] = g->bullets[g->bullet_count - 1]; g->bullet_count--; @@ -66,9 +70,12 @@ void bullet_update(Game *g, float dt) { } b->x += dx/d * step; b->y += dy/d * step; - /* trail */ + /* trail — denser muzzle streak for non-ballistic shells */ if (b->kind != 0) particle_spawn(g, b->x, b->y, 2, 255, 180, 60); + if (b->kind == 1 || b->kind == 3) + particle_spawn(g, b->x - dx / d * 3.0f, b->y - dy / d * 3.0f, + 3, 255, 160, 50); } } diff --git a/engine-c/src/render.c b/engine-c/src/render.c index 32f50ef..98fae58 100644 --- a/engine-c/src/render.c +++ b/engine-c/src/render.c @@ -293,17 +293,33 @@ void render_bullets(Game *g) { } } +/* Soft disc for smoke/fire particles (parity with snapshot disc FX). */ +static void draw_particle_disc(SDL_Renderer *ren, int cx, int cy, int rad, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) { + SDL_SetRenderDrawColor(ren, r, g, b, a); + for (int j = -rad; j <= rad; j++) { + int half = (int)sqrtf((float)(rad * rad - j * j)); + SDL_RenderDrawLine(ren, cx - half, cy + j, cx + half, cy + j); + } +} + void render_particles(Game *g) { - /* Larger combat FX (parity with snapshot particle sizes). */ + /* Kind-aware combat FX: discs for smoke/fire, rects for sparks/debris. */ for (int i = 0; i < g->particle_count; i++) { Particle *p = &g->particles[i]; int sx = (int)(p->x - g->cam.x), sy = (int)(p->y - g->cam.y); float life_a = p->life / (p->max_life > 0 ? p->max_life : 1.0f); if (life_a < 0.12f) continue; Uint8 a = (Uint8)(255 * life_a); - SDL_SetRenderDrawColor(g->ren, p->r, p->g, p->b, a); + Uint8 rr = (Uint8)(p->r * life_a), gg = (Uint8)(p->g * life_a), + bb = (Uint8)(p->b * life_a); int sz = (p->kind == 1) ? 5 : (p->kind == 3) ? 3 : (p->kind == 0) ? 4 : 3; - SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - sz/2, sy - sz/2, sz + 1, sz + 1 }); + if (p->kind == 0 || p->kind == 1) { + draw_particle_disc(g->ren, sx, sy, sz + 1, rr, gg, bb, a); + } else { + SDL_SetRenderDrawColor(g->ren, rr, gg, bb, a); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - sz/2, sy - sz/2, sz + 1, sz + 1 }); + } } } diff --git a/engine-c/src/sprites.c b/engine-c/src/sprites.c index 5e34c82..59e49eb 100644 --- a/engine-c/src/sprites.c +++ b/engine-c/src/sprites.c @@ -76,100 +76,103 @@ SDL_Texture *sprites_make_unit(SDL_Renderer *r, UnitType t, Faction f) { SDL_Color base = faction_color(f); SDL_Color dark = darken(base, 0.55f); SDL_Color lite = lighten(base, 0.45f); - SDL_Color metal = { 60, 60, 70, 255 }; + /* Tyre / mid-tone parity with snapshot draw_unit (mr/mg/mb). */ + const Uint8 tr = 70, tg = 65, tb = 58; const Uint8 ok = 18, og = 16, ob = 14; /* near-black outline */ + (void)dark; switch (t) { case UT_INFANTRY: disc(s, 15, 15, 9, ok, og, ob, 255); disc(s, 15, 15, 7, base.r, base.g, base.b, 255); - disc(s, 15, 12, 3, lite.r, lite.g, lite.b, 255); - line(s, 15, 15, 15, 2, ok, og, ob, 255); /* rifle */ + disc(s, 15, 11, 4, lite.r, lite.g, lite.b, 255); + line(s, 15, 15, 15, 1, ok, og, ob, 255); /* rifle */ break; case UT_BUGGY: - fill_rect(s, 5, 8, 20, 14, ok, og, ob, 255); - fill_rect(s, 7, 10, 16, 10, base.r, base.g, base.b, 255); - disc(s, 10, 8, 3, metal.r, metal.g, metal.b, 255); - disc(s, 20, 8, 3, metal.r, metal.g, metal.b, 255); - disc(s, 10, 22, 3, metal.r, metal.g, metal.b, 255); - disc(s, 20, 22, 3, metal.r, metal.g, metal.b, 255); - line(s, 15, 15, 28, 15, ok, og, ob, 255); + fill_rect(s, 3, 7, 24, 16, ok, og, ob, 255); + fill_rect(s, 5, 9, 20, 12, base.r, base.g, base.b, 255); + fill_rect(s, 7, 11, 16, 8, lite.r, lite.g, lite.b, 255); /* mid body */ + disc(s, 8, 7, 4, tr, tg, tb, 255); + disc(s, 22, 7, 4, tr, tg, tb, 255); + disc(s, 8, 23, 4, tr, tg, tb, 255); + disc(s, 22, 23, 4, tr, tg, tb, 255); + line(s, 15, 15, 29, 15, ok, og, ob, 255); break; case UT_TANK: - fill_rect(s, 4, 9, 22, 13, ok, og, ob, 255); - fill_rect(s, 6, 11, 18, 9, base.r, base.g, base.b, 255); - disc(s, 15, 15, 6, lite.r, lite.g, lite.b, 255); + fill_rect(s, 2, 8, 26, 14, ok, og, ob, 255); + fill_rect(s, 4, 10, 22, 10, base.r, base.g, base.b, 255); + disc(s, 15, 15, 7, lite.r, lite.g, lite.b, 255); line(s, 15, 15, 30, 15, ok, og, ob, 255); - disc(s, 9, 22, 3, ok, og, ob, 255); - disc(s, 21, 22, 3, ok, og, ob, 255); + disc(s, 8, 23, 4, tr, tg, tb, 255); + disc(s, 22, 23, 4, tr, tg, tb, 255); break; case UT_ARTILLERY: - fill_rect(s, 4, 10, 22, 11, ok, og, ob, 255); - fill_rect(s, 6, 12, 18, 7, base.r, base.g, base.b, 255); - disc(s, 15, 15, 5, lite.r, lite.g, lite.b, 255); - line(s, 15, 15, 4, 4, ok, og, ob, 255); - line(s, 15, 15, 26, 26, ok, og, ob, 255); + fill_rect(s, 2, 10, 26, 12, ok, og, ob, 255); + fill_rect(s, 4, 12, 22, 8, base.r, base.g, base.b, 255); + disc(s, 15, 15, 6, lite.r, lite.g, lite.b, 255); + line(s, 15, 15, 3, 3, ok, og, ob, 255); + line(s, 15, 15, 27, 27, ok, og, ob, 255); break; case UT_HARVESTER: - fill_rect(s, 3, 7, 24, 16, ok, og, ob, 255); - fill_rect(s, 5, 9, 20, 12, dark.r, dark.g, dark.b, 255); - fill_rect(s, 6, 10, 18, 10, 180, 150, 70, 255); /* scrap bed */ - disc(s, 9, 22, 3, ok, og, ob, 255); - disc(s, 21, 22, 3, ok, og, ob, 255); - line(s, 6, 8, 6, 4, base.r, base.g, base.b, 255); + fill_rect(s, 1, 6, 28, 18, ok, og, ob, 255); + fill_rect(s, 3, 8, 24, 14, base.r, base.g, base.b, 255); + fill_rect(s, 5, 10, 20, 10, 200, 170, 90, 255); /* scrap bed */ + disc(s, 8, 23, 4, tr, tg, tb, 255); + disc(s, 22, 23, 4, tr, tg, tb, 255); + line(s, 5, 7, 5, 2, lite.r, lite.g, lite.b, 255); break; case UT_JEEP: - fill_rect(s, 6, 10, 18, 11, ok, og, ob, 255); - fill_rect(s, 8, 12, 14, 7, base.r, base.g, base.b, 255); - disc(s, 10, 21, 3, metal.r, metal.g, metal.b, 255); - disc(s, 20, 21, 3, metal.r, metal.g, metal.b, 255); - line(s, 15, 12, 15, 5, base.r, base.g, base.b, 255); /* roll bar */ - line(s, 15, 15, 27, 15, ok, og, ob, 255); + fill_rect(s, 4, 9, 22, 12, ok, og, ob, 255); + fill_rect(s, 6, 11, 18, 8, base.r, base.g, base.b, 255); + disc(s, 9, 22, 4, tr, tg, tb, 255); + disc(s, 21, 22, 4, tr, tg, tb, 255); + line(s, 15, 11, 15, 3, lite.r, lite.g, lite.b, 255); /* roll bar */ + line(s, 15, 15, 28, 15, ok, og, ob, 255); break; case UT_MUTANT: disc(s, 15, 16, 10, ok, og, ob, 255); - disc(s, 15, 14, 7, base.r, base.g, base.b, 255); - disc(s, 15, 11, 3, lite.r, lite.g, lite.b, 255); - line(s, 15, 16, 23, 10, ok, og, ob, 255); /* arm/club */ + disc(s, 15, 14, 8, base.r, base.g, base.b, 255); + disc(s, 15, 10, 4, lite.r, lite.g, lite.b, 255); + line(s, 15, 16, 24, 9, ok, og, ob, 255); /* arm/club */ break; case UT_BEAST: - fill_rect(s, 7, 10, 16, 11, ok, og, ob, 255); - fill_rect(s, 9, 12, 12, 7, base.r, base.g, base.b, 255); - disc(s, 10, 20, 2, ok, og, ob, 255); - disc(s, 14, 21, 2, ok, og, ob, 255); - disc(s, 18, 20, 2, ok, og, ob, 255); - disc(s, 22, 21, 2, ok, og, ob, 255); - disc(s, 22, 13, 4, lite.r, lite.g, lite.b, 255); + fill_rect(s, 5, 9, 20, 12, ok, og, ob, 255); + fill_rect(s, 7, 11, 16, 8, base.r, base.g, base.b, 255); + disc(s, 9, 21, 3, tr, tg, tb, 255); + disc(s, 14, 22, 3, tr, tg, tb, 255); + disc(s, 19, 21, 3, tr, tg, tb, 255); + disc(s, 23, 22, 3, tr, tg, tb, 255); + disc(s, 23, 12, 5, lite.r, lite.g, lite.b, 255); break; case UT_RAVAGER: - fill_rect(s, 2, 8, 26, 15, ok, og, ob, 255); - fill_rect(s, 5, 11, 20, 9, base.r, base.g, base.b, 255); - disc(s, 15, 15, 7, lite.r, lite.g, lite.b, 255); + fill_rect(s, 0, 7, 30, 16, ok, og, ob, 255); + fill_rect(s, 2, 9, 26, 12, base.r, base.g, base.b, 255); + disc(s, 15, 15, 8, lite.r, lite.g, lite.b, 255); line(s, 15, 15, 29, 15, ok, og, ob, 255); /* big barrel */ - disc(s, 8, 22, 3, ok, og, ob, 255); - disc(s, 22, 22, 3, ok, og, ob, 255); + disc(s, 7, 23, 4, tr, tg, tb, 255); + disc(s, 23, 23, 4, tr, tg, tb, 255); break; case UT_FLAME: - fill_rect(s, 7, 11, 16, 14, ok, og, ob, 255); - fill_rect(s, 9, 13, 12, 10, base.r, base.g, base.b, 255); - disc(s, 15, 11, 4, lite.r, lite.g, lite.b, 255); - line(s, 15, 15, 27, 19, 220, 120, 40, 255); /* flame nozzle */ + fill_rect(s, 5, 11, 20, 15, ok, og, ob, 255); + fill_rect(s, 7, 13, 16, 11, base.r, base.g, base.b, 255); + disc(s, 15, 10, 5, lite.r, lite.g, lite.b, 255); + line(s, 15, 15, 28, 20, 255, 150, 50, 255); /* flame nozzle */ break; case UT_MISSILE: - fill_rect(s, 6, 11, 18, 13, ok, og, ob, 255); - fill_rect(s, 8, 13, 14, 9, base.r, base.g, base.b, 255); - disc(s, 10, 22, 3, metal.r, metal.g, metal.b, 255); - disc(s, 20, 22, 3, metal.r, metal.g, metal.b, 255); - line(s, 15, 15, 28, 8, 200, 60, 60, 255); /* launcher */ + fill_rect(s, 4, 11, 22, 14, ok, og, ob, 255); + fill_rect(s, 6, 13, 18, 10, base.r, base.g, base.b, 255); + disc(s, 9, 23, 4, tr, tg, tb, 255); + disc(s, 21, 23, 4, tr, tg, tb, 255); + line(s, 15, 15, 28, 6, 255, 80, 60, 255); /* launcher */ break; case UT_MEDIC: - fill_rect(s, 7, 10, 16, 14, ok, og, ob, 255); - fill_rect(s, 8, 11, 14, 12, 235, 235, 235, 255); /* white ambulance body */ - disc(s, 11, 23, 3, metal.r, metal.g, metal.b, 255); - disc(s, 19, 23, 3, metal.r, metal.g, metal.b, 255); - disc(s, 15, 10, 4, 220, 60, 60, 255); /* red cross */ - fill_rect(s, 14, 7, 2, 6, 255, 255, 255, 255); - fill_rect(s, 12, 9, 6, 2, 255, 255, 255, 255); + fill_rect(s, 5, 10, 20, 15, ok, og, ob, 255); + fill_rect(s, 7, 12, 16, 11, 245, 245, 245, 255); /* white ambulance */ + disc(s, 10, 24, 4, tr, tg, tb, 255); + disc(s, 20, 24, 4, tr, tg, tb, 255); + disc(s, 15, 9, 5, 240, 50, 50, 255); /* red cross */ + fill_rect(s, 14, 5, 3, 8, 255, 255, 255, 255); + fill_rect(s, 11, 8, 8, 3, 255, 255, 255, 255); break; default: disc(s, 15, 15, 10, ok, og, ob, 255);