diff --git a/engine-c/openkknd b/engine-c/openkknd index aeca623..1848619 100755 Binary files a/engine-c/openkknd and b/engine-c/openkknd differ diff --git a/engine-c/src/config.c b/engine-c/src/config.c index 4982516..03d6bcd 100644 --- a/engine-c/src/config.c +++ b/engine-c/src/config.c @@ -175,9 +175,9 @@ const char *unit_name(UnitType t, Faction f) { SDL_Color faction_color(Faction f) { switch (f) { - case FACTION_SURVIVOR: return (SDL_Color){ 90, 160, 70, 255 }; /* olive green */ - case FACTION_EVOLVED: return (SDL_Color){170, 70, 180, 255 }; /* mutant purple */ - case FACTION_SERIES9: return (SDL_Color){200, 200, 60, 255 }; + case FACTION_SURVIVOR: return (SDL_Color){ 55, 235, 55, 255 }; /* lime Survivors */ + case FACTION_EVOLVED: return (SDL_Color){255, 40, 255, 255 }; /* hot magenta Evolved */ + case FACTION_SERIES9: return (SDL_Color){240, 55, 240, 255 }; default: return (SDL_Color){140, 140, 140, 255 }; } } diff --git a/engine-c/src/render.c b/engine-c/src/render.c index 3b2690a..1623418 100644 --- a/engine-c/src/render.c +++ b/engine-c/src/render.c @@ -166,7 +166,8 @@ void render_units(Game *g) { int tx = (int)(u->x / TILE), ty = (int)(u->y / TILE); if (!map_in_bounds(&g->map, tx, ty) || g->map.fog[ty*g->map.w + tx] != 2) continue; } - int sz = 28; + /* Match snapshot SHOT_UNIT_SCALE 1.45 → live silhouette ~41px */ + int sz = 41; SDL_Texture *tex = g->spr.unit[u->type][u->faction]; draw_tex_world(g, tex, u->x, u->y, sz, sz, u->heading, 255); /* selection ring */ @@ -174,21 +175,21 @@ void render_units(Game *g) { int cx = (int)(u->x - g->cam.x), cy = (int)(u->y - g->cam.y); SDL_SetRenderDrawColor(g->ren, 120, 255, 120, 220); for (int a = 0; a < 360; a += 12) { - int px = cx + (int)(cosf(a*3.14159f/180)*16); - int py = cy + (int)(sinf(a*3.14159f/180)*16); + int px = cx + (int)(cosf(a*3.14159f/180)*22); + int py = cy + (int)(sinf(a*3.14159f/180)*22); SDL_RenderDrawPoint(g->ren, px, py); } } /* health bar */ if (u->hp < u->max_hp || u->selected) { - int cx = (int)(u->x - g->cam.x), by = (int)(u->y - g->cam.y) - 18; - int bw = 24; + int cx = (int)(u->x - g->cam.x), by = (int)(u->y - g->cam.y) - 26; + int bw = 32; SDL_Rect bg = { cx - bw/2, by, bw, 4 }; SDL_SetRenderDrawColor(g->ren, 50, 50, 50, 255); SDL_RenderFillRect(g->ren, &bg); float f = u->hp / u->max_hp; - SDL_Color c = (u->faction == FACTION_SURVIVOR) ? (SDL_Color){90,200,90,255} - : (SDL_Color){220,110,220,255}; + SDL_Color c = (u->faction == FACTION_SURVIVOR) ? (SDL_Color){55,235,55,255} + : (SDL_Color){255,40,255,255}; SDL_Rect fg = { cx - bw/2, by, (int)(bw * f), 4 }; SDL_SetRenderDrawColor(g->ren, c.r, c.g, c.b, 255); SDL_RenderFillRect(g->ren, &fg); @@ -203,9 +204,57 @@ void render_units(Game *g) { } void render_bullets(Game *g) { + /* Kind-aware tracers / shells with streak tails (parity with snapshot.c). */ for (int i = 0; i < g->bullet_count; i++) { Bullet *b = &g->bullets[i]; int sx = (int)(b->x - g->cam.x), sy = (int)(b->y - g->cam.y); + float dx = b->tx - b->x, dy = b->ty - b->y; + float d = sqrtf(dx * dx + dy * dy); + if (d > 1.0f) { + float ux = dx / d, uy = dy / d; + int len = (b->kind == 2) ? 24 : (b->kind == 3) ? 18 + : (b->kind == 1) ? 14 : 10; + for (int t = 1; t <= len; t++) { + int tx = sx - (int)(ux * (float)t * 0.75f); + int ty = sy - (int)(uy * (float)t * 0.75f); + Uint8 fade = (Uint8)(255 - t * 9); + if (b->kind == 2) { + /* laser: cyan→magenta streak */ + SDL_SetRenderDrawColor(g->ren, fade, 80, 255, 220); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ tx - 1, ty - 1, + (t < 3) ? 3 : 2, (t < 3) ? 3 : 2 }); + SDL_SetRenderDrawColor(g->ren, 220, 180, 255, 255); + SDL_RenderDrawPoint(g->ren, tx, ty); + } else if (b->kind == 3) { + SDL_SetRenderDrawColor(g->ren, 255, (Uint8)(120 - t * 4), 30, 230); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ tx - 1, ty - 1, + (t < 4) ? 3 : 2, (t < 4) ? 3 : 2 }); + } else { + SDL_SetRenderDrawColor(g->ren, 255, (Uint8)(200 - t * 8), 50, 220); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ tx, ty, 2, 2 }); + } + } + } + int rad = (b->kind == 1 || b->kind == 3) ? 6 : 4; + SDL_SetRenderDrawColor(g->ren, 255, 160, 40, 255); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - rad - 1, sy - rad - 1, + (rad + 1) * 2, (rad + 1) * 2 }); + SDL_SetRenderDrawColor(g->ren, 255, 240, 140, 255); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - rad, sy - rad, rad * 2, rad * 2 }); + if (b->kind == 2) { + SDL_SetRenderDrawColor(g->ren, 120, 200, 255, 255); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - rad - 1, sy - rad - 1, + (rad + 1) * 2, (rad + 1) * 2 }); + SDL_SetRenderDrawColor(g->ren, 240, 220, 255, 255); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - (rad - 1), sy - (rad - 1), + (rad - 1) * 2, (rad - 1) * 2 }); + } else if (b->kind == 3) { + SDL_SetRenderDrawColor(g->ren, 255, 70, 30, 240); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx - 5, sy - 1, 6, 6 }); + SDL_SetRenderDrawColor(g->ren, 255, 200, 80, 240); + SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx, sy - 4, 4, 4 }); + } + /* Keep sprite head as bright core on top of procedural tracer. */ SDL_Texture *tex = g->spr.bullet[b->kind < 4 ? b->kind : 0]; SDL_Rect r = { sx - 5, sy - 5, 10, 10 }; SDL_RenderCopy(g->ren, tex, NULL, &r); @@ -213,13 +262,16 @@ void render_bullets(Game *g) { } void render_particles(Game *g) { + /* Larger combat FX (parity with snapshot particle sizes). */ 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); - Uint8 a = (Uint8)(255 * (p->life / p->max_life)); + 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); - int sz = (p->kind == 1) ? 3 : 2; - SDL_RenderFillRect(g->ren, &(SDL_Rect){ sx-sz/2, sy-sz/2, sz, sz }); + 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 }); } } @@ -471,7 +523,7 @@ void render_minimap(Game *g) { case T_WATER: cr=44;cg=78;cb=120; break; case T_ROCK: cr=110;cg=104;cb=98; break; case T_SCRAP: cr=200;cg=170;cb=70; break; - case T_GRASS: cr=86;cg=120;cb=64; break; + case T_GRASS: cr=210;cg=170;cb=78; break; /* arid wasteland */ } if (fv == 1) { cr/=2; cg/=2; cb/=2; } SDL_SetRenderDrawColor(g->ren, cr, cg, cb, 255); diff --git a/engine-c/src/sprites.c b/engine-c/src/sprites.c index f8ae7d4..f319e9f 100644 --- a/engine-c/src/sprites.c +++ b/engine-c/src/sprites.c @@ -69,6 +69,7 @@ static SDL_Color lighten(SDL_Color c, float f) { } /* ---------------- unit sprites ---------------- */ +/* Near-black outline first (KKND2 silhouette), then bright faction fill. */ SDL_Texture *sprites_make_unit(SDL_Renderer *r, UnitType t, Faction f) { int S = 30; SDL_Surface *s = new_surf(S, S); @@ -76,85 +77,93 @@ SDL_Texture *sprites_make_unit(SDL_Renderer *r, UnitType t, Faction f) { SDL_Color dark = darken(base, 0.55f); SDL_Color lite = lighten(base, 0.45f); SDL_Color metal = { 60, 60, 70, 255 }; + const Uint8 ok = 18, og = 16, ob = 14; /* near-black outline */ switch (t) { case UT_INFANTRY: - disc(s, 15, 15, 8, dark.r, dark.g, dark.b, 255); - disc(s, 15, 15, 6, base.r, base.g, base.b, 255); + 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, 30, 30, 30, 255); /* rifle */ + line(s, 15, 15, 15, 2, ok, og, ob, 255); /* rifle */ break; case UT_BUGGY: - fill_rect(s, 6, 9, 18, 12, dark.r, dark.g, dark.b, 255); - fill_rect(s, 8, 11, 14, 8, base.r, base.g, base.b, 255); + 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, 30, 30, 30, 255); + line(s, 15, 15, 28, 15, ok, og, ob, 255); break; case UT_TANK: - fill_rect(s, 5, 10, 20, 11, dark.r, dark.g, dark.b, 255); - fill_rect(s, 7, 12, 16, 7, base.r, base.g, base.b, 255); + 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); - line(s, 15, 15, 30, 15, 40, 40, 45, 255); - disc(s, 9, 22, 3, 30, 30, 30, 255); - disc(s, 21, 22, 3, 30, 30, 30, 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); break; case UT_ARTILLERY: - fill_rect(s, 5, 11, 20, 9, dark.r, dark.g, dark.b, 255); + 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, 40, 40, 45, 255); - line(s, 15, 15, 26, 26, 40, 40, 45, 255); + line(s, 15, 15, 4, 4, ok, og, ob, 255); + line(s, 15, 15, 26, 26, ok, og, ob, 255); break; case UT_HARVESTER: - fill_rect(s, 4, 8, 22, 14, dark.r, dark.g, dark.b, 255); - fill_rect(s, 6, 10, 18, 10, 110, 90, 50, 255); /* scrap bed */ - disc(s, 9, 22, 3, 30, 30, 30, 255); - disc(s, 21, 22, 3, 30, 30, 30, 255); + 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); break; case UT_JEEP: - fill_rect(s, 7, 11, 16, 9, dark.r, dark.g, dark.b, 255); + 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, 40, 40, 45, 255); + line(s, 15, 15, 27, 15, ok, og, ob, 255); break; case UT_MUTANT: - disc(s, 15, 16, 9, dark.r, dark.g, dark.b, 255); - disc(s, 15, 14, 6, base.r, base.g, base.b, 255); + 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, 30, 30, 30, 255); /* arm/club */ + line(s, 15, 16, 23, 10, ok, og, ob, 255); /* arm/club */ break; case UT_BEAST: - fill_rect(s, 8, 11, 14, 9, dark.r, dark.g, dark.b, 255); - disc(s, 10, 20, 2, 30, 30, 30, 255); - disc(s, 14, 21, 2, 30, 30, 30, 255); - disc(s, 18, 20, 2, 30, 30, 30, 255); - disc(s, 22, 21, 2, 30, 30, 30, 255); - disc(s, 22, 13, 4, base.r, base.g, base.b, 255); + 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); break; case UT_RAVAGER: - fill_rect(s, 3, 9, 24, 13, dark.r, dark.g, dark.b, 255); - fill_rect(s, 6, 12, 18, 7, base.r, base.g, base.b, 255); + 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); - line(s, 15, 15, 29, 15, 40, 40, 45, 255); /* big barrel */ - disc(s, 8, 22, 3, 30, 30, 30, 255); - disc(s, 22, 22, 3, 30, 30, 30, 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); break; case UT_FLAME: - fill_rect(s, 8, 12, 14, 12, dark.r, dark.g, dark.b, 255); - disc(s, 15, 11, 4, base.r, base.g, base.b, 255); + 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 */ break; case UT_MISSILE: - fill_rect(s, 7, 12, 16, 11, dark.r, dark.g, dark.b, 255); + 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 */ 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); @@ -163,7 +172,8 @@ SDL_Texture *sprites_make_unit(SDL_Renderer *r, UnitType t, Faction f) { fill_rect(s, 12, 9, 6, 2, 255, 255, 255, 255); break; default: - disc(s, 15, 15, 9, base.r, base.g, base.b, 255); + disc(s, 15, 15, 10, ok, og, ob, 255); + disc(s, 15, 15, 8, base.r, base.g, base.b, 255); break; } SDL_Texture *tex = SDL_CreateTextureFromSurface(r, s); @@ -179,11 +189,14 @@ SDL_Texture *sprites_make_bld(SDL_Renderer *r, BuildingType t, Faction f) { SDL_Color base = faction_color(f); SDL_Color dark = darken(base, 0.5f); SDL_Color lite = lighten(base, 0.4f); - SDL_Color wall = { 90, 84, 78, 255 }; - SDL_Color wall2 = { 64, 60, 56, 255 }; + /* Bright sand pad + dark ridge outline (arid wasteland plate). */ + SDL_Color wall = { 198, 168, 108, 255 }; + SDL_Color wall2 = { 155, 128, 78, 255 }; + const Uint8 ok = 28, og = 24, ob = 18; fill_rect(s, 0, 0, W, H, wall2.r, wall2.g, wall2.b, 255); - fill_rect(s, 3, 3, W - 6, H - 6, wall.r, wall.g, wall.b, 255); + fill_rect(s, 2, 2, W - 4, H - 4, ok, og, ob, 255); + fill_rect(s, 4, 4, W - 8, H - 8, wall.r, wall.g, wall.b, 255); ring(s, W/2, H/2, (W>B, G slightly under R). */ switch (t) { - case T_WASTELAND: tr=120; tg=104; tb=78; break; - case T_RUBBLE: tr=96; tg=86; tb=74; break; - case T_ROAD: tr=70; tg=68; tb=64; break; - case T_GRASS: tr=86; tg=120; tb=64; break; - case T_WATER: tr=44; tg=78; tb=120; break; - case T_ROCK: tr=110; tg=104; tb=98; break; - case T_SCRAP: tr=110; tg=96; tb=70; break; - default: tr=120; tg=104; tb=78; break; + case T_WASTELAND: tr=228; tg=188; tb=98; break; + case T_RUBBLE: tr=168; tg=138; tb=88; break; + case T_ROAD: tr=175; tg=148; tb=98; break; + case T_GRASS: tr=242; tg=198; tb=92; break; /* sunlit desert */ + case T_WATER: tr=72; tg=128; tb=178; break; + case T_ROCK: tr=155; tg=142; tb=128; break; + case T_SCRAP: tr=240; tg=190; tb=78; break; + default: tr=228; tg=188; tb=98; break; } fill_rect(s, 0, 0, TILE, TILE, tr, tg, tb, 255); /* speckle for texture */