495 lines
22 KiB
C
495 lines
22 KiB
C
#include "kknd.h"
|
|
|
|
/* =========================================================================
|
|
* sprites.c - Procedural 2D sprite/terrain generation.
|
|
* Recreates the chunky post-apocalyptic KKND look without using any
|
|
* original game assets. All art is drawn at runtime into SDL textures.
|
|
* ========================================================================= */
|
|
|
|
#define SURF_FMT SDL_PIXELFORMAT_RGBA32
|
|
|
|
static SDL_Surface *new_surf(int w, int h) {
|
|
return SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SURF_FMT);
|
|
}
|
|
|
|
static void px(SDL_Surface *s, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
if (x < 0 || y < 0 || x >= s->w || y >= s->h) return;
|
|
Uint32 *p = (Uint32 *)((Uint8 *)s->pixels + y * s->pitch);
|
|
Uint32 pix = (a << 24) | (b << 16) | (g << 8) | r;
|
|
p[x] = pix;
|
|
}
|
|
|
|
static void fill_rect(SDL_Surface *s, int x, int y, int w, int h,
|
|
Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
for (int j = y; j < y + h; j++)
|
|
for (int i = x; i < x + w; i++)
|
|
px(s, i, j, r, g, b, a);
|
|
}
|
|
|
|
static void disc(SDL_Surface *s, int cx, int cy, int rad,
|
|
Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
for (int j = -rad; j <= rad; j++)
|
|
for (int i = -rad; i <= rad; i++)
|
|
if (i*i + j*j <= rad*rad)
|
|
px(s, cx + i, cy + j, r, g, b, a);
|
|
}
|
|
|
|
static void ring(SDL_Surface *s, int cx, int cy, int rad, int t,
|
|
Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
for (int j = -rad; j <= rad; j++)
|
|
for (int i = -rad; i <= rad; i++) {
|
|
int d = i*i + j*j;
|
|
if (d <= rad*rad && d >= (rad - t)*(rad - t))
|
|
px(s, cx + i, cy + j, r, g, b, a);
|
|
}
|
|
}
|
|
|
|
static void line(SDL_Surface *s, int x0, int y0, int x1, int y1,
|
|
Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
|
int dx = abs(x1 - x0), dy = -abs(y1 - y0);
|
|
int sx = x0 < x1 ? 1 : -1, sy = y0 < y1 ? 1 : -1;
|
|
int err = dx + dy;
|
|
for (;;) {
|
|
px(s, x0, y0, r, g, b, a);
|
|
if (x0 == x1 && y0 == y1) break;
|
|
int e2 = 2 * err;
|
|
if (e2 >= dy) { err += dy; x0 += sx; }
|
|
if (e2 <= dx) { err += dx; y0 += sy; }
|
|
}
|
|
}
|
|
|
|
static SDL_Color darken(SDL_Color c, float f) {
|
|
return (SDL_Color){
|
|
(Uint8)(c.r*f), (Uint8)(c.g*f), (Uint8)(c.b*f), c.a };
|
|
}
|
|
static SDL_Color lighten(SDL_Color c, float f) {
|
|
return (SDL_Color){
|
|
(Uint8)(c.r + (255-c.r)*f), (Uint8)(c.g + (255-c.g)*f),
|
|
(Uint8)(c.b + (255-c.b)*f), c.a };
|
|
}
|
|
|
|
/* ---------------- unit sprites ---------------- */
|
|
/* Near-black outline first (KKND2 silhouette), then bright faction fill.
|
|
* Geometry mirrors snapshot.c draw_unit atlas coords (center 15,15); SDL rotates live. */
|
|
SDL_Texture *sprites_make_unit(SDL_Renderer *r, UnitType t, Faction f) {
|
|
int S = 30;
|
|
SDL_Surface *s = new_surf(S, S);
|
|
SDL_Color base = faction_color(f);
|
|
SDL_Color dark = darken(base, 0.55f);
|
|
SDL_Color lite = lighten(base, 0.45f);
|
|
/* 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:
|
|
/* legs → torso → helmet → rifle */
|
|
disc(s, 11, 23, 3, ok, og, ob, 255);
|
|
disc(s, 19, 23, 3, ok, og, ob, 255);
|
|
disc(s, 11, 23, 2, base.r, base.g, base.b, 255);
|
|
disc(s, 19, 23, 2, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 15, 8, ok, og, ob, 255);
|
|
disc(s, 15, 15, 6, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 9, 4, ok, og, ob, 255);
|
|
disc(s, 15, 9, 3, lite.r, lite.g, lite.b, 255);
|
|
line(s, 16, 14, 16, 1, 40, 36, 30, 255);
|
|
line(s, 17, 14, 17, 2, 55, 50, 40, 255);
|
|
break;
|
|
case UT_BUGGY:
|
|
/* cabin + windshield + chassis + wheels */
|
|
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, 6, 9, 10, 6, lite.r, lite.g, lite.b, 255); /* cabin */
|
|
fill_rect(s, 7, 8, 8, 3, 35, 55, 75, 255); /* windshield */
|
|
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, 40, 36, 30, 255);
|
|
break;
|
|
case UT_TANK:
|
|
/* side tracks + hull + cupola + thick barrel */
|
|
fill_rect(s, 2, 8, 5, 12, ok, og, ob, 255);
|
|
fill_rect(s, 23, 8, 5, 12, ok, og, ob, 255);
|
|
fill_rect(s, 3, 10, 3, 10, tr, tg, tb, 255);
|
|
fill_rect(s, 24, 10, 3, 10, tr, tg, tb, 255);
|
|
fill_rect(s, 4, 10, 22, 10, ok, og, ob, 255);
|
|
fill_rect(s, 6, 11, 18, 8, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 15, 6, ok, og, ob, 255);
|
|
disc(s, 15, 15, 5, lite.r, lite.g, lite.b, 255); /* cupola */
|
|
disc(s, 15, 12, 2, 40, 38, 32, 255); /* hatch */
|
|
line(s, 15, 14, 29, 14, 50, 45, 35, 255);
|
|
line(s, 15, 15, 29, 15, 50, 45, 35, 255);
|
|
line(s, 15, 16, 28, 16, 50, 45, 35, 255);
|
|
disc(s, 8, 23, 4, tr, tg, tb, 255);
|
|
disc(s, 22, 23, 4, tr, tg, tb, 255);
|
|
break;
|
|
case UT_ARTILLERY:
|
|
/* chassis + long barrel tube + muzzle */
|
|
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, 5, ok, og, ob, 255);
|
|
disc(s, 15, 15, 4, lite.r, lite.g, lite.b, 255);
|
|
line(s, 15, 14, 4, 3, 50, 45, 35, 255);
|
|
line(s, 15, 15, 3, 2, 55, 50, 40, 255);
|
|
line(s, 15, 16, 4, 4, 50, 45, 35, 255);
|
|
disc(s, 4, 3, 2, 60, 55, 45, 255); /* muzzle */
|
|
disc(s, 8, 23, 3, tr, tg, tb, 255);
|
|
disc(s, 22, 23, 3, tr, tg, tb, 255);
|
|
break;
|
|
case UT_HARVESTER:
|
|
/* cabin nose + scrap bed ridges + wheels */
|
|
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, 3, 8, 8, 8, lite.r, lite.g, lite.b, 255); /* cabin */
|
|
fill_rect(s, 4, 8, 6, 3, 35, 55, 75, 255); /* cabin glass */
|
|
fill_rect(s, 11, 10, 14, 10, 200, 170, 90, 255); /* bed */
|
|
line(s, 14, 10, 26, 10, 160, 130, 70, 255);
|
|
line(s, 14, 13, 26, 13, 160, 130, 70, 255);
|
|
line(s, 14, 16, 26, 16, 160, 130, 70, 255);
|
|
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:
|
|
/* open cabin + roll bar + MG */
|
|
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);
|
|
fill_rect(s, 7, 10, 8, 5, lite.r, lite.g, lite.b, 255);
|
|
disc(s, 9, 22, 4, tr, tg, tb, 255);
|
|
disc(s, 21, 22, 4, tr, tg, tb, 255);
|
|
line(s, 11, 11, 11, 3, lite.r, lite.g, lite.b, 255);
|
|
line(s, 19, 11, 19, 3, lite.r, lite.g, lite.b, 255);
|
|
line(s, 11, 3, 19, 3, lite.r, lite.g, lite.b, 255);
|
|
line(s, 15, 15, 28, 15, 50, 45, 35, 255);
|
|
break;
|
|
case UT_MUTANT:
|
|
/* hunched body + spikes + claws */
|
|
disc(s, 15, 17, 10, ok, og, ob, 255);
|
|
disc(s, 15, 15, 8, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 9, 4, ok, og, ob, 255);
|
|
disc(s, 15, 9, 3, lite.r, lite.g, lite.b, 255);
|
|
line(s, 12, 6, 10, 1, 40, 36, 30, 255); /* back spike */
|
|
line(s, 15, 5, 15, 0, 40, 36, 30, 255);
|
|
line(s, 18, 6, 20, 1, 40, 36, 30, 255);
|
|
line(s, 15, 16, 26, 8, 40, 36, 30, 255); /* claw arm */
|
|
line(s, 24, 9, 28, 6, 55, 50, 40, 255);
|
|
line(s, 24, 9, 28, 11, 55, 50, 40, 255);
|
|
disc(s, 10, 22, 3, ok, og, ob, 255);
|
|
disc(s, 20, 22, 3, ok, og, ob, 255);
|
|
disc(s, 10, 22, 2, base.r, base.g, base.b, 255);
|
|
disc(s, 20, 22, 2, base.r, base.g, base.b, 255);
|
|
break;
|
|
case UT_BEAST:
|
|
/* chunky body + snout + multi-wheel */
|
|
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, 24, 12, 5, ok, og, ob, 255);
|
|
disc(s, 24, 12, 4, lite.r, lite.g, lite.b, 255); /* snout */
|
|
line(s, 26, 12, 29, 12, 40, 36, 30, 255);
|
|
break;
|
|
case UT_RAVAGER:
|
|
/* heavy hull + side skirts + big barrel */
|
|
fill_rect(s, 0, 7, 5, 14, ok, og, ob, 255);
|
|
fill_rect(s, 25, 7, 5, 14, ok, og, ob, 255);
|
|
fill_rect(s, 2, 9, 26, 12, ok, og, ob, 255);
|
|
fill_rect(s, 4, 10, 22, 10, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 15, 7, ok, og, ob, 255);
|
|
disc(s, 15, 15, 6, lite.r, lite.g, lite.b, 255);
|
|
line(s, 15, 14, 29, 14, 50, 45, 35, 255);
|
|
line(s, 15, 15, 29, 15, 50, 45, 35, 255);
|
|
line(s, 15, 16, 28, 16, 50, 45, 35, 255);
|
|
disc(s, 7, 23, 4, tr, tg, tb, 255);
|
|
disc(s, 23, 23, 4, tr, tg, tb, 255);
|
|
break;
|
|
case UT_FLAME:
|
|
/* backpack fuel tank + nozzle + body */
|
|
fill_rect(s, 7, 12, 16, 12, ok, og, ob, 255);
|
|
fill_rect(s, 9, 14, 12, 9, base.r, base.g, base.b, 255);
|
|
disc(s, 15, 9, 4, ok, og, ob, 255);
|
|
disc(s, 15, 9, 3, lite.r, lite.g, lite.b, 255);
|
|
disc(s, 8, 14, 5, ok, og, ob, 255); /* fuel tank */
|
|
disc(s, 8, 14, 4, 90, 70, 40, 255);
|
|
disc(s, 8, 14, 2, 200, 120, 40, 255);
|
|
line(s, 18, 15, 28, 20, 255, 150, 50, 255);
|
|
line(s, 18, 16, 27, 21, 255, 180, 60, 255);
|
|
disc(s, 28, 20, 2, 255, 200, 80, 255);
|
|
break;
|
|
case UT_MISSILE:
|
|
/* launcher rails + tubes on wheeled chassis */
|
|
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);
|
|
fill_rect(s, 11, 6, 10, 4, ok, og, ob, 255);
|
|
fill_rect(s, 12, 6, 8, 2, 255, 80, 60, 255);
|
|
fill_rect(s, 11, 11, 10, 4, ok, og, ob, 255);
|
|
fill_rect(s, 12, 11, 8, 2, 255, 100, 70, 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);
|
|
break;
|
|
case UT_MEDIC:
|
|
fill_rect(s, 5, 10, 20, 15, ok, og, ob, 255);
|
|
fill_rect(s, 7, 12, 16, 11, 245, 245, 245, 255); /* white ambulance */
|
|
fill_rect(s, 6, 9, 6, 4, 200, 220, 240, 255); /* cab glass */
|
|
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);
|
|
disc(s, 15, 15, 8, base.r, base.g, base.b, 255);
|
|
break;
|
|
}
|
|
SDL_Texture *tex = SDL_CreateTextureFromSurface(r, s);
|
|
SDL_FreeSurface(s);
|
|
return tex;
|
|
}
|
|
|
|
/* ---------------- building sprites ---------------- */
|
|
/* Bright concrete pad + BT_* interiors (parity with snapshot draw_bld). */
|
|
SDL_Texture *sprites_make_bld(SDL_Renderer *r, BuildingType t, Faction f) {
|
|
int w = bld_def(t)->w, h = bld_def(t)->h;
|
|
int W = w * TILE, H = h * TILE;
|
|
SDL_Surface *s = new_surf(W, H);
|
|
SDL_Color base = faction_color(f);
|
|
SDL_Color dark = darken(base, 0.5f);
|
|
SDL_Color lite = lighten(base, 0.35f);
|
|
const Uint8 ok = 22, og = 20, ob = 16;
|
|
const Uint8 wall = 205, wall2 = 175;
|
|
|
|
/* Bright concrete pad on arid sand */
|
|
fill_rect(s, 0, 0, W, H, ok, og, ob, 255);
|
|
fill_rect(s, 2, 2, W - 4, H - 4, 210, 185, 130, 255);
|
|
fill_rect(s, 4, 4, W - 8, H - 8, wall2, (Uint8)(wall2 - 18), (Uint8)(wall2 - 45), 255);
|
|
fill_rect(s, 5, 5, W - 10, H - 10, wall, (Uint8)(wall - 22), (Uint8)(wall - 55), 255);
|
|
fill_rect(s, 5, 5, W - 10, 6, (Uint8)(wall + 30), (Uint8)(wall + 10), (Uint8)(wall - 20), 255);
|
|
|
|
switch (t) {
|
|
case BT_BASE:
|
|
/* multi-wing HQ: side wings + centre block + dome + mast (parity draw_bld) */
|
|
fill_rect(s, 4, 18, 18, 28, ok, og, ob, 255);
|
|
fill_rect(s, 6, 20, 14, 24, base.r, base.g, base.b, 255);
|
|
fill_rect(s, W - 22, 18, 18, 28, ok, og, ob, 255);
|
|
fill_rect(s, W - 20, 20, 14, 24, base.r, base.g, base.b, 255);
|
|
fill_rect(s, 16, 10, W - 32, H - 20, ok, og, ob, 255);
|
|
fill_rect(s, 18, 12, W - 36, H - 24, base.r, base.g, base.b, 255);
|
|
fill_rect(s, 20, 14, W - 40, 8, lite.r, lite.g, lite.b, 255);
|
|
disc(s, W/2, H/2 - 2, 12, ok, og, ob, 255);
|
|
disc(s, W/2, H/2 - 2, 10, lite.r, lite.g, lite.b, 255);
|
|
disc(s, W/2, H/2 - 2, 5, 255, 250, 180, 255);
|
|
fill_rect(s, W/2 - 2, 4, 4, H/2 - 8, 200, 180, 60, 255);
|
|
fill_rect(s, W/2 - 5, 4, 10, 3, 220, 210, 80, 255);
|
|
fill_rect(s, W/2 - 6, H - 14, 12, 6, 40, 38, 34, 255);
|
|
break;
|
|
case BT_WARFACTORY:
|
|
/* hangar shell + ridge vents + dark bay door */
|
|
fill_rect(s, 4, 6, W - 8, H - 12, ok, og, ob, 255);
|
|
fill_rect(s, 6, 8, W - 12, H - 16, base.r, base.g, base.b, 255);
|
|
fill_rect(s, 8, 10, W - 16, 10, lite.r, lite.g, lite.b, 255);
|
|
fill_rect(s, 10, 12, 6, 6, 55, 50, 42, 255);
|
|
fill_rect(s, W/2 - 3, 12, 6, 6, 55, 50, 42, 255);
|
|
fill_rect(s, W - 16, 12, 6, 6, 55, 50, 42, 255);
|
|
fill_rect(s, 10, H - 28, W - 20, 18, ok, og, ob, 255);
|
|
fill_rect(s, 12, H - 26, W - 24, 14, 35, 35, 40, 255);
|
|
line(s, W/2, H - 26, W/2, H - 12, 70, 68, 60, 255);
|
|
fill_rect(s, 8, H - 10, W - 16, 4, 50, 48, 42, 255);
|
|
break;
|
|
case BT_REFINERY:
|
|
/* twin silos + pipe/conveyor slab + hopper */
|
|
disc(s, 18, H/2 - 2, 14, ok, og, ob, 255);
|
|
disc(s, 18, H/2 - 2, 12, 200, 165, 85, 255);
|
|
ring(s, 18, H/2 - 2, 9, 2, 90, 70, 45, 255);
|
|
disc(s, W - 18, H/2 - 2, 14, ok, og, ob, 255);
|
|
disc(s, W - 18, H/2 - 2, 12, 190, 155, 75, 255);
|
|
ring(s, W - 18, H/2 - 2, 9, 2, 90, 70, 45, 255);
|
|
fill_rect(s, 14, H - 16, W - 28, 10, ok, og, ob, 255);
|
|
fill_rect(s, 16, H - 14, W - 32, 6, 140, 110, 55, 255);
|
|
line(s, 18, H/2 + 8, W - 18, H - 12, 110, 90, 50, 255);
|
|
line(s, 18, H/2 + 10, W - 18, H - 10, 110, 90, 50, 255);
|
|
fill_rect(s, W/2 - 6, 8, 12, 14, ok, og, ob, 255);
|
|
fill_rect(s, W/2 - 4, 10, 8, 10, base.r, base.g, base.b, 255);
|
|
break;
|
|
case BT_POWER:
|
|
/* cooling towers + reactor core + steam cross */
|
|
disc(s, W/2 - 6, H/2 + 2, 8, ok, og, ob, 255);
|
|
disc(s, W/2 - 6, H/2 + 2, 6, 100, 160, 210, 255);
|
|
disc(s, W/2 + 6, H/2 + 2, 8, ok, og, ob, 255);
|
|
disc(s, W/2 + 6, H/2 + 2, 6, 90, 150, 200, 255);
|
|
fill_rect(s, 6, 6, W - 12, 10, ok, og, ob, 255);
|
|
fill_rect(s, 8, 7, W - 16, 7, 70, 120, 170, 255);
|
|
disc(s, W/2, 10, 4, 250, 252, 255, 255);
|
|
line(s, W/2, 4, W/2, H - 4, 230, 245, 255, 255);
|
|
line(s, 4, H/2, W - 4, H/2, 200, 230, 250, 255);
|
|
fill_rect(s, W/2 - 2, H - 8, 4, 5, 55, 50, 42, 255);
|
|
break;
|
|
case BT_TURRET:
|
|
/* bunker base + cupola + thick barrel */
|
|
fill_rect(s, 3, H - 12, W - 6, 10, ok, og, ob, 255);
|
|
fill_rect(s, 5, H - 10, W - 10, 7, 55, 50, 42, 255);
|
|
disc(s, W/2, H/2 + 1, W/3 + 2, ok, og, ob, 255);
|
|
disc(s, W/2, H/2 + 1, W/3, base.r, base.g, base.b, 255);
|
|
disc(s, W/2, H/2 + 1, W/5, lite.r, lite.g, lite.b, 255);
|
|
disc(s, W/2, H/2 - 1, 3, 40, 38, 32, 255);
|
|
line(s, W/2, H/2, W/2 + 13, H/2 - 12, 30, 28, 24, 255);
|
|
line(s, W/2 + 1, H/2 + 1, W/2 + 13, H/2 - 11, 50, 45, 35, 255);
|
|
disc(s, W/2 + 12, H/2 - 11, 2, 255, 200, 80, 255);
|
|
break;
|
|
case BT_WALL:
|
|
/* battlement blocks + ridge + shadow seam */
|
|
fill_rect(s, 1, 1, W - 2, H - 2, ok, og, ob, 255);
|
|
fill_rect(s, 2, 6, W - 4, H - 8, 175, 155, 120, 255);
|
|
fill_rect(s, 2, 2, 7, 8, 195, 175, 140, 255);
|
|
fill_rect(s, 12, 2, 7, 8, 195, 175, 140, 255);
|
|
fill_rect(s, 22, 2, 7, 8, 195, 175, 140, 255);
|
|
fill_rect(s, 3, 10, W - 6, 4, 210, 190, 150, 255);
|
|
line(s, 2, H/2, W - 2, H/2, 60, 52, 42, 255);
|
|
line(s, W/2, 6, W/2, H - 2, 70, 60, 48, 255);
|
|
break;
|
|
case BT_REPAIR:
|
|
/* garage bay + crane arm + green service mark */
|
|
fill_rect(s, 5, 8, W - 10, H - 14, ok, og, ob, 255);
|
|
fill_rect(s, 7, 10, W - 14, H - 18, base.r, base.g, base.b, 255);
|
|
fill_rect(s, 10, H - 26, W - 20, 14, 40, 38, 34, 255);
|
|
fill_rect(s, 12, H - 24, W - 24, 10, 55, 52, 48, 255);
|
|
fill_rect(s, W - 18, 8, 10, 6, ok, og, ob, 255);
|
|
fill_rect(s, W - 16, 10, 6, 22, 90, 85, 70, 255);
|
|
line(s, W - 13, 12, 14, 18, 120, 110, 90, 255);
|
|
line(s, W - 13, 13, 14, 19, 100, 90, 70, 255);
|
|
ring(s, W/2 - 4, H/2 + 2, 8, 2, 120, 220, 120, 255);
|
|
line(s, W/2 - 10, H/2 + 2, W/2 + 2, H/2 + 2, 120, 220, 120, 255);
|
|
line(s, W/2 - 4, H/2 - 4, W/2 - 4, H/2 + 8, 120, 220, 120, 255);
|
|
break;
|
|
case BT_RESEARCH:
|
|
/* lab block + dish + instrument stubs */
|
|
fill_rect(s, 6, 14, W - 12, H - 20, ok, og, ob, 255);
|
|
fill_rect(s, 8, 16, W - 16, H - 24, base.r, base.g, base.b, 255);
|
|
fill_rect(s, 10, 18, W - 20, 8, lite.r, lite.g, lite.b, 255);
|
|
disc(s, W/2 + 6, 14, 12, ok, og, ob, 255);
|
|
disc(s, W/2 + 6, 14, 10, 210, 180, 80, 255);
|
|
ring(s, W/2 + 6, 14, 7, 2, 180, 150, 60, 255);
|
|
disc(s, W/2 + 6, 14, 3, 255, 240, 160, 255);
|
|
fill_rect(s, 12, H - 18, 6, 8, 230, 230, 160, 255);
|
|
fill_rect(s, 22, H - 20, 5, 10, 230, 230, 160, 255);
|
|
line(s, W/2 + 6, 4, W/2 + 6, 14, 200, 190, 120, 255);
|
|
break;
|
|
default:
|
|
(void)dark;
|
|
break;
|
|
}
|
|
SDL_Texture *tex = SDL_CreateTextureFromSurface(r, s);
|
|
SDL_FreeSurface(s);
|
|
return tex;
|
|
}
|
|
|
|
/* ---------------- terrain tiles ---------------- */
|
|
SDL_Texture *sprites_make_terrain(SDL_Renderer *r, TerrainType t) {
|
|
SDL_Surface *s = new_surf(TILE, TILE);
|
|
Uint8 tr=0,tg=0,tb=0;
|
|
/* Classic KKND2 wasteland: yellow-tan sand (R>>B, G slightly under R). */
|
|
switch (t) {
|
|
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 */
|
|
for (int i = 0; i < 40; i++) {
|
|
int x = (i*73) % TILE, y = (i*131) % TILE;
|
|
int v = ((i*53) % 24) - 12;
|
|
px(s, x, y,
|
|
(Uint8)kknd_clampi(tr+v,0,255),
|
|
(Uint8)kknd_clampi(tg+v,0,255),
|
|
(Uint8)kknd_clampi(tb+v,0,255), 255);
|
|
}
|
|
if (t == T_SCRAP) {
|
|
for (int i = 0; i < 10; i++) {
|
|
int x = (i*97) % TILE, y = (i*61) % TILE;
|
|
disc(s, x, y, 2, 180, 150, 60, 255);
|
|
}
|
|
}
|
|
if (t == T_WATER) {
|
|
for (int i = 0; i < TILE; i += 4)
|
|
line(s, 0, i, TILE, i, 60, 100, 150, 255);
|
|
}
|
|
if (t == T_ROCK) {
|
|
for (int i = 0; i < 12; i++) {
|
|
int x = (i*89) % TILE, y = (i*149) % TILE;
|
|
disc(s, x, y, 3, 130, 124, 118, 255);
|
|
}
|
|
}
|
|
SDL_Texture *tex = SDL_CreateTextureFromSurface(r, s);
|
|
SDL_FreeSurface(s);
|
|
return tex;
|
|
}
|
|
|
|
/* ---------------- bullets ---------------- */
|
|
static SDL_Texture *make_bullet(SDL_Renderer *r, int kind) {
|
|
int S = 10;
|
|
SDL_Surface *s = new_surf(S, S);
|
|
switch (kind) {
|
|
case 0: disc(s, 5, 5, 3, 255, 230, 120, 255); break; /* MG tracer */
|
|
case 1: disc(s, 5, 5, 4, 255, 160, 60, 255); break; /* shell */
|
|
case 2: disc(s, 5, 5, 3, 120, 255, 160, 255); break; /* laser */
|
|
case 3: disc(s, 5, 5, 4, 255, 90, 90, 255); break; /* missile */
|
|
default: disc(s, 5, 5, 3, 255, 255, 255, 255);
|
|
}
|
|
SDL_Texture *tex = SDL_CreateTextureFromSurface(r, s);
|
|
SDL_FreeSurface(s);
|
|
return tex;
|
|
}
|
|
|
|
int sprites_init(Sprites *sp, SDL_Renderer *r) {
|
|
memset(sp, 0, sizeof(Sprites));
|
|
for (int t = 0; t < T_COUNT; t++)
|
|
sp->terrain[t] = sprites_make_terrain(r, (TerrainType)t);
|
|
for (int t = 1; t < UT_COUNT; t++) {
|
|
sp->unit[t][FACTION_SURVIVOR] = sprites_make_unit(r, (UnitType)t, FACTION_SURVIVOR);
|
|
sp->unit[t][FACTION_EVOLVED] = sprites_make_unit(r, (UnitType)t, FACTION_EVOLVED);
|
|
sp->unit[t][FACTION_SERIES9] = sprites_make_unit(r, (UnitType)t, FACTION_SERIES9);
|
|
}
|
|
for (int t = 1; t < BT_COUNT; t++) {
|
|
sp->bld[t][FACTION_SURVIVOR] = sprites_make_bld(r, (BuildingType)t, FACTION_SURVIVOR);
|
|
sp->bld[t][FACTION_EVOLVED] = sprites_make_bld(r, (BuildingType)t, FACTION_EVOLVED);
|
|
sp->bld[t][FACTION_SERIES9] = sprites_make_bld(r, (BuildingType)t, FACTION_SERIES9);
|
|
}
|
|
for (int k = 0; k < 4; k++)
|
|
sp->bullet[k] = make_bullet(r, k);
|
|
|
|
sp->font_small = TTF_OpenFont("/usr/share/fonts/TTF/DejaVuSans.ttf", 14);
|
|
if (!sp->font_small)
|
|
sp->font_small = TTF_OpenFont("/usr/share/fonts/gnu-free/FreeSans.ttf", 14);
|
|
sp->font_med = sp->font_small ? TTF_OpenFont("/usr/share/fonts/TTF/DejaVuSans.ttf", 20) : NULL;
|
|
sp->font_big = sp->font_small ? TTF_OpenFont("/usr/share/fonts/TTF/DejaVuSans.ttf", 34) : NULL;
|
|
if (!sp->font_small) {
|
|
sp->font_small = TTF_OpenFont("/usr/share/fonts/TTF/DejaVuSans-Bold.ttf", 14);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void sprites_free(Sprites *sp) {
|
|
for (int t = 0; t < T_COUNT; t++)
|
|
if (sp->terrain[t]) SDL_DestroyTexture(sp->terrain[t]);
|
|
for (int t = 1; t < UT_COUNT; t++)
|
|
for (int f = 0; f < MAX_FACTIONS; f++)
|
|
if (sp->unit[t][f]) SDL_DestroyTexture(sp->unit[t][f]);
|
|
for (int t = 1; t < BT_COUNT; t++)
|
|
for (int f = 0; f < MAX_FACTIONS; f++)
|
|
if (sp->bld[t][f]) SDL_DestroyTexture(sp->bld[t][f]);
|
|
for (int k = 0; k < 4; k++)
|
|
if (sp->bullet[k]) SDL_DestroyTexture(sp->bullet[k]);
|
|
if (sp->font_small) TTF_CloseFont(sp->font_small);
|
|
if (sp->font_med) TTF_CloseFont(sp->font_med);
|
|
if (sp->font_big) TTF_CloseFont(sp->font_big);
|
|
}
|