Newer
Older
cneboy_games / test / test.c
#include <client_api.h>
#include "parse.h"

#define GRID 14
#define COLS 12
#define ROWS 10
#define PADX 0
#define PADY 2
#define SPRITEOFF -1

pbm_t* player;
pbm_t* player_out;

typedef enum
{
    BG_SOLID = 1,
    BG_TOP = 2,
} bg_flags;

typedef struct
{
    char* tile;
    pbm_t* pbm;
    uint8_t flags;
} bg_t;

bg_t bg[100];
int num_bg = 0;

typedef enum
{
    GRID_FLIPX = 1,
    GRID_FLIPY = 2,
} grid_flags;

typedef struct
{
    uint8_t tile;
    grid_flags flags;
} grid_t;

grid_t grid[COLS][ROWS];

#define OUTLINE 2

bool load_level(char* fname);
void unload_bg();

int setup(int a)
{
    player = f_bitmap("/player.pbm");
    player_out = d_expand_bitmap(player, OUTLINE, true, false);

    if (!load_level("/level14.txt"))
    {
        return 1;
    }

    return 0;
}

char* last_level = NULL;
void unload_bg()
{
    for (int i = 0; i < num_bg; i++)
    {
        free(bg[i].pbm);
    }
    num_bg = 0;

    if (last_level)
    {
        free(last_level);
        last_level = NULL;
    }
}

#define SOLID 1
#define TOP 2


bool is_space(char c) { return isspace(c); }
bool is_comma_or_space(char c) { return c == ',' || is_space(c); }

bool load_level(char* fname)
{
    unload_bg();
    memset(grid, 0, sizeof(grid));

    size_t len;
    last_level = (char*)f_contents(fname, &len);
    if (!last_level)
    {
        printf("Couldn't find level: %s\n", fname);
        return false;
    }

    reset_parse = true;

    // name, file, [flags]
    char* tile_def[] = { NULL, NULL, NULL };

    while (true)
    {
        int res = parse(last_level, len, is_space, false);
        //printf("Parse res: %d\n", res);

        if (res == DONE)
        {
            printf("No tile grid given in level %s\n", fname);
            return false;
        }

        int not_null = 0;
        for (; not_null < 3; not_null++)
        {
            if (!tile_def[not_null]) break;
        }

        if (res == NL)
        {
            if (not_null < 2)
            {
                printf("Invalid tile def on line %d\n", parse_line - 1);
                return false;
            }

            printf("Parsed tile %d %s %s %s\n", not_null, tile_def[0], tile_def[1], tile_def[2]);

            bg_flags flags = 0;
            if (not_null >= 3)
            {
                size_t flag_len = strlen(tile_def[2]);
                for (int i = 0; i < flag_len; i++)
                {
                    if (tile_def[2][i] == 's') flags |= BG_SOLID;
                    if (tile_def[2][i] == 't') flags |= BG_TOP;
                }
            }


            bool found = false;
            char f[100];
            sprintf(f, "/%s.pbm", tile_def[1]);
            pbm_t* n = f_bitmap(f);
            if (n)
            {
                found = true;

                bg_t b = { tile_def[0], n, flags };
                bg[num_bg++] = b;

                printf("Tile %s registered as word %s\n", f, tile_def[0]);
            }
            else
            {
                int i = 1;
                sprintf(f, "/%s%d.pbm", tile_def[1], i);
                while (n = f_bitmap(f))
                {
                    found = true;

                    char name[10];
                    sprintf(name, "%s%d", tile_def[0], i);


                    bg_t b = { malloc(strlen(name) + 1), n, flags }; 
                    strcpy(b.tile, name);
                    bg[num_bg++] = b;

                    printf("Tile %s registered as word %s\n", f, name);

                    i++;
                    sprintf(f, "/%s%d.pbm", tile_def[1], i);
                }
            }

            if (!found)
            {
                printf("Not found: graphic with name %s\n", tile_def[1]);
            }

            memset(tile_def, 0, sizeof(tile_def));
            continue;
        }

        if (res == BREAK) break;

        if (not_null < 3)
        {
            tile_def[not_null++] = parse_word;
        }
        else
        {
            printf("Too many words on line %d\n", parse_line);
        }
    }

    int x = 0;
    int y = 0;
    while (true)
    {
        int res = parse(last_level, len, is_comma_or_space, false);
        //printf("Parse res: %d\n", res);
        if (res == DONE || res == BREAK)
        {
            if (y < ROWS)
            {
                printf("Didn't read full grid, only %d,%d\n", x, y);
                return false;
            }
            break;
        }
        if (res == NL)
        {
            if (x < COLS)
            {
                printf("Couldn't read full row, only to index %d on line %d\n", x - 1, parse_line);
                return false;
            }
            x = 0;
            y++;
        }
        if (res == WORD)
        {
            if (x >= COLS || y >= ROWS)
            {
                printf("Grid is too big, reached %d,%d on line %d\n", x, y, parse_line);
                return false;
            }
            char* prob = NULL;
            grid_flags flags = 0;
            for (int i = 0; i < 2; i++)
            {
                if (parse_word[0] == '-')
                {
                    flags |= GRID_FLIPX;
                    parse_word++;
                }
                else if (parse_word[0] == '!')
                {
                    flags |= GRID_FLIPY;
                    parse_word++;
                }
            }

            size_t l = strlen(parse_word);
            for (int i = 0; i < l; i++)
            {
                if (parse_word[i] == '.')
                {
                    parse_word[i] = 0;
                    prob = parse_word + (i + 1);
                    break;
                }
            }

            //printf("Searching %s\n", parse_word);
            for (int i = 0; i < num_bg; i++)
            {
                //printf("  Check %s\n", bg[i].tile);
                if (strcmp(bg[i].tile, parse_word) == 0)
                {
                    if (prob)
                    {
                        int p = max(0, min(9, atoi(prob)));
                        if (random(1, 10) > p) continue;
                    }
                    //printf("Tile %d on %d,%d\n", i, x, y);
                    grid_t g = { i + 1, flags };
                    grid[x][y] = g;
                }
            }

            x++;

        }
    }


    return 0;
}

float x = 0;
float y = 0;
int rot = 0;

float speed = 80;

bool flipX = false, flipY = false;

void d_pbm_outline(int16_t x, int16_t y, pbm_t* pbm)
{
    for (int i = x - 1; i <= x + 1; i++)
    {
        for (int j = y - 1; j <= y + 1; j++)
        {
            d_pbm(i, j, pbm, 0, 0, 0, 0, WHITE, TRANSPARENT, R_NONE, false, false);
        }
    }
}

bool move_debug = false;

bool r_intersect(int x1, int y1, int w1, int h1,
                 int x2, int y2, int w2, int h2)
{
    if (x1 >= x2 + w2 ||
        x1 + w2 <= x2 ||
        y1 >= y2 + h2 ||
        y1 + h2 <= y2) return false;
    if (move_debug) printf("INTERSECT [%d,%d + %d,%d]   [%d,%d + %d,%d]\n", x1, y1, w1, h1, x2, y2, w2, h2);
    return true;
}

bool r_free(int x, int y, int w, int h)
{
    int minX = x / GRID;
    int maxX = (x + w - 1) / GRID;
    int minY = y / GRID;
    int maxY = (y + h - 1) / GRID;

    for (int i = max(0, minX); i <= min(COLS - 1, maxX); i++)
    {
        for (int j = max(0, minY); j <= min(ROWS - 1, maxY); j++)
        {
            if (grid[i][j].tile != 0 && (bg[grid[i][j].tile - 1].flags & SOLID))
            {
                if (r_intersect(x, y, w, h,
                                i * GRID + 1,
                                j * GRID + 1,
                                GRID - 2,
                                GRID - 2)) return false;
            }
        }
    }
    return true;
}


int loop(int ms)
{
    d_clear();

    for (int i = 0; i < COLS; i++)
    {
        for (int j = 0; j < ROWS; j++)
        {
            if (grid[i][j].tile != 0 && !(bg[grid[i][j].tile - 1].flags & TOP))
            {
                d_pbm(
                        PADX + i * GRID + SPRITEOFF,
                        PADY + j * GRID + SPRITEOFF,
                        bg[grid[i][j].tile - 1].pbm,
                        0,0,0,0, BLACK, TRANSPARENT, R_NONE, grid[i][j].flags & GRID_FLIPX, grid[i][j].flags & GRID_FLIPY);
            }
        }
    }

    //d_fillRect(0, 0, SCREEN_W, SCREEN_H, BLACK);


    d_pbm(
        (uint16_t)roundf(x) - OUTLINE + PADX + SPRITEOFF,
        (uint16_t)roundf(y) - OUTLINE + PADY + SPRITEOFF,
            player_out, 0, 0, 0, 0, WHITE, TRANSPARENT, rot, flipX, flipY);
    d_pbm(
        (uint16_t)roundf(x) + PADX + SPRITEOFF,
        (uint16_t)roundf(y) + PADY + SPRITEOFF,
            player, 0, 0, 0, 0, BLACK, TRANSPARENT, rot, flipX, flipY);

    for (int i = 0; i < COLS; i++)
    {
        for (int j = 0; j < ROWS; j++)
        {
            if (grid[i][j].tile != 0 && (bg[grid[i][j].tile - 1].flags & TOP))
            {
                d_fillRect(
                        PADX + i * GRID,
                        PADY + j * GRID,
                        GRID, GRID,
                        WHITE
                        );
            }
        }
    }

    for (int i = 0; i < COLS; i++)
    {
        for (int j = 0; j < ROWS; j++)
        {
            if (grid[i][j].tile != 0 && (bg[grid[i][j].tile - 1].flags & TOP))
            {
                d_pbm(
                        PADX + i * GRID + SPRITEOFF,
                        PADY + j * GRID + SPRITEOFF,
                        bg[grid[i][j].tile - 1].pbm,
                        0,0,0,0, BLACK, TRANSPARENT, R_NONE, grid[i][j].flags & GRID_FLIPX, grid[i][j].flags & GRID_FLIPY);
            }
        }
    }

    /*
    if (button_pressed(BUTTON_A))
    {
        rot = (rot + 1) % 4;
    }
    if (button_pressed(BUTTON_B))
    {
        flipX = !flipX;
        if (!flipX)
        {
            flipY = !flipY;
        }
        printf("Flip: %d %d\n", flipX, flipY);
    }
    */

    float ox = x;
    float oy = y;

    int ox_i = (int)roundf(ox);
    int oy_i = (int)roundf(oy);

    float t = ms / 1000.0f;
    if (button_down(DPAD_RIGHT)) x += t * speed;
    if (button_down(DPAD_LEFT)) x -= t * speed;
    if (button_down(DPAD_DOWN)) y += t * speed;
    if (button_down(DPAD_UP)) y -= t * speed;

    if (button_pressed(BUTTON_A)) move_debug = !move_debug;

    if (x != ox || y != oy)
    {
        int x_i = (int)roundf(x);
        int y_i = (int)roundf(y);

        if (x > ox) x_i = (int)roundf(x + 0.5f);
        if (x < ox) x_i = (int)roundf(x - 0.5f);

        if (y > oy) y_i = (int)roundf(y + 0.5f);
        if (y < oy) y_i = (int)roundf(y - 0.5f);

        bool goX = ox_i != x_i;
        bool goY = oy_i != y_i;

        if (move_debug) printf("(%f,%f)->(%f,%f) I: (%d,%d)->(%d,%d) [%d, %d]\n", ox, oy, x, y, ox_i, oy_i, x_i, y_i, goX, goY);

        while (goX || goY)
        {
            if (goX)
            {
                int testX = ox_i < x_i ? ox_i + 1 : ox_i - 1;
                bool test = r_free(testX + 1, oy_i + 1, GRID - 2, GRID - 2);
                if (move_debug) printf("testX: %d => %d\n", testX, test);
                if (test)
                {
                    ox_i = testX;
                    if (ox_i == x_i) goX = false;
                    if (move_debug) printf("ox_i = %d, goX = %d\n", ox_i, goX);
                }
                else
                {
                    goX = false;
                    if (move_debug) printf("goX = false\n");
                }
            }
            if (goY)
            {
                int testY = oy_i < y_i ? oy_i + 1 : oy_i - 1;
                bool test = r_free(ox_i + 1, testY + 1, GRID - 2, GRID - 2);
                if (move_debug) printf("testY: %d => %d\n", testY, test);
                if (test)
                {
                    oy_i = testY;
                    if (oy_i == y_i) goY = false;
                    if (move_debug) printf("oy_i = %d, goY = %d\n", oy_i, goY);
                }
                else
                {
                    goY = false;
                    if (move_debug) printf("goY = false\n");
                }
            }
        }

        if (ox_i != x_i) x = ox_i;
        if (oy_i != y_i) y = oy_i;
        if (move_debug) printf("reached (%d,%d) on target of (%d,%d), x,y=(%f,%f)\n", ox_i, oy_i, x_i, y_i, x, y);

        if (move_debug) printf("\n====================\n\n");
    }

    return 0;
}