jtmm2/src/level.c

282 lines
5.5 KiB
C
Raw Permalink Normal View History

2021-12-16 13:56:02 +01:00
#include "level.h"
2021-12-16 15:57:50 +01:00
#include "conf.h"
2021-12-21 00:14:49 +01:00
#include "missile.h"
2021-12-17 23:07:06 +01:00
#include "player.h"
2021-12-18 11:02:33 +01:00
#include "polarity.h"
2021-12-17 00:20:39 +01:00
#include "tile.h"
2021-12-20 12:06:32 +01:00
#include "util.h"
2021-12-17 18:44:13 +01:00
#include "vec.h"
2021-12-16 15:57:50 +01:00
#include "visual_data.h"
2022-01-12 22:36:10 +01:00
#include <fcntl.h>
2021-12-16 15:57:50 +01:00
#include <gint/display.h>
2021-12-16 13:56:02 +01:00
#include <stdlib.h>
2022-01-12 22:36:10 +01:00
#include <sys/stat.h>
#include <unistd.h>
2021-12-16 13:56:02 +01:00
static struct Level level;
2022-01-12 23:10:31 +01:00
struct LevelBin *user_level = NULL;
2021-12-16 15:57:50 +01:00
extern bopti_image_t bimg_tileset;
2021-12-16 13:56:02 +01:00
2021-12-18 18:24:17 +01:00
extern struct LevelBin kble_test, kble_burn, kble_bounce, kble_worm, kble_shake,
2021-12-20 18:21:15 +01:00
kble_tilt, kble_cave, kble_headtrauma, kble_gimmick, kble_failure,
2021-12-21 21:50:32 +01:00
kble_design, kble_safe, kble_harder;
2021-12-18 12:47:35 +01:00
static const struct LevelBinNamed levels[] = {
2021-12-18 18:24:17 +01:00
{&kble_test, "gentle introduction"},
2021-12-21 18:32:22 +01:00
{&kble_safe, "area 102"},
2021-12-21 21:50:32 +01:00
{&kble_harder, "harder the fall"},
2021-12-20 18:21:15 +01:00
{&kble_design, "this is my design"},
2021-12-20 15:29:34 +01:00
{&kble_failure, "insert a coin"},
2021-12-19 18:13:43 +01:00
{&kble_cave, "the light at the end of the tunnel"},
2021-12-19 23:02:51 +01:00
{&kble_gimmick, "sell your gimmick"},
2021-12-19 18:13:43 +01:00
{&kble_headtrauma, "minefield"},
2021-12-18 18:24:17 +01:00
{&kble_burn, "these are rare"},
{&kble_bounce, "deceptive road"},
{&kble_shake, "breaking into reality"},
{&kble_tilt, "tilted"},
2021-12-19 17:53:43 +01:00
{&kble_worm, "under your skin"},
2021-12-18 18:24:17 +01:00
{NULL, NULL}};
2021-12-17 23:07:06 +01:00
2021-12-16 13:56:02 +01:00
static void level_free(void);
2022-01-12 22:36:10 +01:00
static void load(const struct LevelBin *);
2021-12-16 13:56:02 +01:00
void
2021-12-17 23:07:06 +01:00
level_init(struct Player *p)
2021-12-16 13:56:02 +01:00
{
level.data = NULL;
2021-12-16 15:57:50 +01:00
level.visual_data = NULL;
2021-12-17 23:07:06 +01:00
level.player = p;
2021-12-16 13:56:02 +01:00
}
void
level_deinit(void)
{
level_free();
2022-01-12 23:10:31 +01:00
if (user_level != NULL) {
free(user_level);
user_level = NULL;
}
2021-12-16 13:56:02 +01:00
}
void
2021-12-17 23:07:06 +01:00
level_load(int id)
2021-12-16 13:56:02 +01:00
{
2021-12-18 12:47:35 +01:00
const struct LevelBin *const b = levels[id].bin;
2022-01-12 22:36:10 +01:00
load(b);
2021-12-17 23:07:06 +01:00
level.id = id;
2022-01-12 22:36:10 +01:00
}
void
level_save_kble(const char *path)
{
2022-01-12 23:10:31 +01:00
const ssize_t fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
unsigned char data[LEVELBIN_SIZE] = {0};
2022-01-12 22:36:10 +01:00
int i;
data[0] = 0;
data[1] = 1;
data[3] = level.width;
data[5] = level.height;
i = level.size;
while (i-- > 0)
2022-01-12 22:36:10 +01:00
data[i + 6] = level.data[i];
2022-01-12 23:10:31 +01:00
if (fd >= 0) {
2022-01-12 22:36:10 +01:00
write(fd, data, sizeof(data));
close(fd);
}
2021-12-16 13:56:02 +01:00
}
2022-01-12 23:10:31 +01:00
void
level_load_kble(const char *path)
{
const ssize_t fd = open(path, O_RDONLY);
if (user_level == NULL) {
user_level = malloc(LEVELBIN_SIZE);
if (user_level == NULL) return;
}
if (fd >= 0) {
size_t bytes;
bytes = read(fd, user_level, LEVELBIN_SIZE);
close(fd);
if (bytes != LEVELBIN_SIZE) return;
if (user_level->format != 0) return;
if (user_level->chunk_size != 1) return;
if (user_level->width != LEVEL_WIDTH) return;
if (user_level->height != LEVEL_HEIGHT) return;
}
}
void
level_load_kble_followup(void)
{
if (user_level != NULL) {
load(user_level);
level_regen_visual_data(1);
}
}
2021-12-16 13:56:02 +01:00
void
level_reload(void)
{
2021-12-17 23:07:06 +01:00
level_load(level.id);
}
void
level_next(void)
{
2021-12-18 12:47:35 +01:00
if (levels[level.id + 1].bin != NULL)
2021-12-17 23:07:06 +01:00
level_load(level.id + 1);
else
level_reload();
2021-12-16 13:56:02 +01:00
}
2021-12-16 15:57:50 +01:00
void
2021-12-19 00:30:09 +01:00
level_regen_visual_data(int editing)
2021-12-16 15:57:50 +01:00
{
const int tileset_width = bimg_tileset.width / TILE_SIZE;
int y = level.height;
while (y-- > 0) {
int x = level.width;
while (x-- > 0) {
const int i = x + y * level.width;
const int tile = level.data[i];
struct VisualData *const vd = &level.visual_data[i];
vd->x = x * TILE_SIZE;
vd->y = y * TILE_SIZE;
vd->img_x = tile % tileset_width * TILE_SIZE;
vd->img_y = (int)(tile / tileset_width) * TILE_SIZE;
vd->visible = tile != 0;
2021-12-19 00:30:09 +01:00
if (editing) continue;
2021-12-18 11:02:33 +01:00
switch (tile) {
case TILE_RED:
2021-12-19 18:13:43 +01:00
case TILE_BURN_RED:
2021-12-18 11:02:33 +01:00
vd->img_y += polarity() ? TILE_SIZE : 0;
break;
case TILE_BLUE:
2021-12-19 18:13:43 +01:00
case TILE_BURN_BLUE:
2021-12-18 11:02:33 +01:00
vd->img_y += polarity() ? 0 : TILE_SIZE;
break;
default:
break;
}
2021-12-16 15:57:50 +01:00
}
}
}
void
level_draw(void)
{
int i = level.size;
while (i-- > 0) {
const struct VisualData *const vd = &level.visual_data[i];
if (vd->visible) {
2021-12-18 15:55:24 +01:00
dsubimage(vd->x + DRAW_OFF_X, vd->y, &bimg_tileset,
vd->img_x, vd->img_y, TILE_SIZE, TILE_SIZE,
0);
2021-12-16 15:57:50 +01:00
}
}
2021-12-19 00:30:09 +01:00
}
2021-12-18 12:47:35 +01:00
2021-12-19 00:30:09 +01:00
void
level_draw_name(void)
{
2021-12-20 12:06:32 +01:00
dputs_outline(DWIDTH - 4, DHEIGHT - 2, DTEXT_RIGHT, DTEXT_BOTTOM,
levels[level.id].name);
2021-12-16 15:57:50 +01:00
}
2021-12-16 23:27:04 +01:00
int
level_get(int x, int y)
{
if (x < 0 || y < 0 || x >= level.width || y >= level.height)
return TILE_OOB;
return level.data[x + y * level.width];
}
int
level_get_px(int x, int y)
{
return level_get(x / TILE_SIZE, y / TILE_SIZE);
}
2021-12-19 00:30:09 +01:00
void
level_set(int x, int y, int v)
{
if (x < 0 || y < 0 || x >= level.width || y >= level.height) return;
level.data[x + y * level.width] = v;
}
2021-12-20 11:33:34 +01:00
void
level_set_px(int x, int y, int v)
{
level_set(x / TILE_SIZE, y / TILE_SIZE, v);
}
2021-12-17 18:44:13 +01:00
struct Vec
level_find(enum Tile t)
{
int i = level.size;
while (i-- > 0 && level.data[i] != t)
;
return (struct Vec){i % level.width, i / level.width};
}
2021-12-21 00:14:49 +01:00
int
level_count(enum Tile t)
{
int c = 0;
int i = level.size;
while (i-- > 0)
c += level.data[i] == t;
return c;
}
2022-01-12 22:36:10 +01:00
static void
load(const struct LevelBin *b)
{
int i = b->width * b->height;
level_free();
level.width = b->width;
level.height = b->height;
level.size = i;
level.data = malloc(i);
level.visual_data = malloc(i * sizeof(struct VisualData));
while (i-- > 0)
level.data[i] = b->data[i];
polarity_reset();
level_regen_visual_data(0);
player_spawn(level.player);
/* missiles */
missile_manager_init();
i = level.size;
while (i-- > 0)
if (level.data[i] == TILE_MISSILE_LAUNCHER)
missile_new(i % level.width * TILE_SIZE + TILE_SIZE / 2,
(int)(i / level.width) * TILE_SIZE +
TILE_SIZE / 2);
}
2021-12-19 00:30:09 +01:00
struct Vec
level_dim(void)
{
return (struct Vec){level.width, level.height};
}
2021-12-16 13:56:02 +01:00
static void
level_free(void)
{
if (level.data != NULL) {
free(level.data);
level.data = NULL;
}
2021-12-16 15:57:50 +01:00
if (level.visual_data != NULL) {
free(level.visual_data);
level.visual_data = NULL;
}
2021-12-16 13:56:02 +01:00
}