Back to shtanton's homepage
summaryrefslogtreecommitdiff
path: root/src/all.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/all.c')
-rw-r--r--src/all.c692
1 files changed, 592 insertions, 100 deletions
diff --git a/src/all.c b/src/all.c
index e8e5b11..cf52eca 100644
--- a/src/all.c
+++ b/src/all.c
@@ -1,103 +1,525 @@
+#ifndef INCLUDE_ALL_C
+#define INCLUDE_ALL_C
+
#include <stddef.h>
#include <stdint.h>
-typedef struct {
- int x, y, w, h;
- unsigned char r, g, b, a;
-} DrawElement;
+#include "types.c"
+#include "levels.c"
+#include "tick.c"
+
+static const Color colors[N_COLORS][4] = {
+ {
+ {255, 255, 255, 255},
+ {255, 255, 255, 255},
+ {255, 255, 255, 255},
+ {255, 255, 255, 255},
+ },
+ {
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+ {0, 0, 0, 255},
+ },
+ {
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ },
+ {
+ {255, 255, 0, 255},
+ {255, 255, 0, 255},
+ {255, 255, 0, 255},
+ {255, 255, 0, 255},
+ },
+ {
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ {255, 255, 0, 255},
+ {255, 255, 0, 255},
+ },
+ {
+ {255, 255, 0, 255},
+ {255, 255, 0, 255},
+ {255, 0, 0, 255},
+ {255, 0, 0, 255},
+ },
+ {
+ {255, 0, 0, 255},
+ {255, 255, 0, 255},
+ {255, 0, 0, 255},
+ {255, 255, 0, 255},
+ },
+ {
+ {255, 255, 0, 255},
+ {255, 0, 0, 255},
+ {255, 255, 0, 255},
+ {255, 0, 0, 255},
+ },
+ {
+ {0, 0, 255, 255},
+ {0, 0, 255, 255},
+ {0, 0, 255, 255},
+ {0, 0, 255, 255},
+ },
+ {
+ {0, 0, 255, 255},
+ {0, 0, 255, 255},
+ {255, 255, 255, 255},
+ {255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255},
+ {255, 255, 255, 255},
+ {0, 0, 255, 255},
+ {0, 0, 255, 255},
+ },
+ {
+ {0, 0, 255, 255},
+ {255, 255, 255, 255},
+ {0, 0, 255, 255},
+ {255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255},
+ {0, 0, 255, 255},
+ {255, 255, 255, 255},
+ {0, 0, 255, 255},
+ },
+};
-typedef struct {
- int len;
- DrawElement els[256];
-} DrawList;
+#define BUTTON_SIZE 32
+#define BUTTON_SPACING 16
+#define BUTTON_SPACER(i) (BUTTON_SPACING + BUTTON_SIZE + (BUTTON_SIZE * (i) + (i) * BUTTON_SPACING))
-#define MEM_SIZE (1<<16)
+// reverse order as they're anchored to bottom
+static const Button buttons[N_BUTTONS] = {
+ [BUTTON_BACK] = {.x = BUTTON_SPACING, .y = BUTTON_SPACER(BUTTON_BACK), .w = BUTTON_SIZE, .h = BUTTON_SIZE},
+ [BUTTON_RETRY] = {.x = BUTTON_SPACING, .y = BUTTON_SPACER(BUTTON_RETRY), .w = BUTTON_SIZE, .h = BUTTON_SIZE},
+ [BUTTON_PLAY] = {.x = BUTTON_SPACING, .y = BUTTON_SPACER(BUTTON_PLAY), .w = BUTTON_SIZE, .h = BUTTON_SIZE},
+ [BUTTON_CONTINUE] = {.x = BUTTON_SPACING, .y = BUTTON_SPACER(BUTTON_CONTINUE), .w = BUTTON_SIZE, .h = BUTTON_SIZE},
+};
-typedef struct {
- char *start;
- char *end;
-} Arena;
-
-#define new(a, c, t) ((t *) alloc(a, c, sizeof(t), _Alignof(t)))
-#define affirm(c) while (!(c)) *(volatile int *)0 = 0
-
-static void *alloc(Arena *a, ptrdiff_t count, ptrdiff_t size, ptrdiff_t align) {
- ptrdiff_t pad = -(size_t) a->start & (align - 1);
- affirm(count < (a->end - a->start - pad) / size);
- char *r = a->start + pad;
- a->start += pad + size * count;
- for (ptrdiff_t i = 0; i < count * size; i++) {
- r[i] = 0;
+// This returns a positive color index or a negated image index
+static int getPlaceAction(int currentColor, int cellx, int celly, float cellWidth, float cellHeight) {
+ int hoverColor = EMPTY;
+
+ // TODO yellow when there are no reds available
+ switch (currentColor) {
+ case BLACK:
+ if (cellx < cellWidth / 4 && cellx < celly && cellx < cellHeight - celly) {
+ hoverColor = RED_LEFT;
+ } else if (celly < cellHeight / 4 && celly < cellx && celly < cellWidth - cellx) {
+ hoverColor = RED_UP;
+ } else if (cellx > cellWidth / 4 * 3 && cellWidth - cellx < celly && cellWidth - cellx < cellHeight - celly) {
+ hoverColor = RED_RIGHT;
+ } else if (celly > cellHeight / 4 * 3 && cellHeight - celly < cellx && cellHeight - celly < cellWidth - cellx) {
+ hoverColor = RED_DOWN;
+ } else {
+ hoverColor = RED;
+ }
+ break;
+ case EMPTY:
+ hoverColor = BLACK;
+ break;
}
- return r;
+ return hoverColor;
}
-typedef struct {
- int width, height;
-} UI;
+static DrawList *render(State *state, UI *ui, Arena *a) {
+ DrawList *drawList = new(a, 1, DrawList);
-typedef struct {
- int x, y;
-} State;
-
-// Mirror these in src/index.html.in
-enum {
- INPUT_NONE,
- INPUT_UP,
- INPUT_DOWN,
- INPUT_LEFT,
- INPUT_RIGHT,
-};
+ float cellWidth = (float) (ui->width - GRID_OFFSET_X) / GRIDWIDTH;
+ float cellHeight = (float) ui->height / GRIDHEIGHT;
+
+ // Actual cells
+ for (int x = 0; x < GRIDWIDTH; x++) {
+ for (int y = 0; y < GRIDHEIGHT; y++) {
+ if (colorImages[(int) state->grid[x + GRIDWIDTH * y]]) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * x + GRID_OFFSET_X,
+ .y = cellHeight * y,
+ .w = cellWidth,
+ .h = cellHeight,
+ .image = (ImageRef) {
+ .index = colorImages[(int) state->grid[x + GRIDWIDTH * y]],
+ .opacity = 255,
+ },
+ };
+ } else {
+ for (int subx = 0; subx < 2; subx++) {
+ for (int suby = 0; suby < 2; suby++) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * x + GRID_OFFSET_X + subx * cellWidth / 2,
+ .y = cellHeight * y + suby * cellHeight / 2,
+ .w = cellWidth / 2 + (1 - subx),
+ .h = cellHeight / 2 + (1 - suby),
+ .fill = colors[(int) state->grid[x + GRIDWIDTH * y]][subx + 2 * suby],
+ };
+ }
+ }
+ }
+ }
+ }
-typedef struct {
- State state;
- UI ui;
- int input;
-} Game;
+ // Vertical grid lines
+ for (int x = 1; x < GRIDWIDTH; x++) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * x + GRID_OFFSET_X,
+ .y = 0,
+ .w = 1,
+ .h = ui->height,
+ .fill = {0, 0, 0, 255},
+ };
+ }
+
+ // Horizontal grid lines
+ for (int y = 1; y < GRIDHEIGHT; y++) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = GRID_OFFSET_X,
+ .y = y * cellHeight,
+ .w = ui->width - GRID_OFFSET_X,
+ .h = 1,
+ .fill = {0, 0, 0, 255},
+ };
+ }
-static DrawList *render(State state, UI *ui, Arena *a) {
- (void) ui;
+ // Spawner
+ if (state->spawnerx != 0 && state->spawnery != 0) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * state->spawnerx + GRID_OFFSET_X,
+ .y = cellHeight * state->spawnery,
+ .w = cellWidth,
+ .h = cellHeight,
+ .fill = {0, 0, 255, 63},
+ .border = {0, 0, 255, 255},
+ };
+ }
- DrawList *drawList = new(a, 1, DrawList);
- drawList->len = 1;
- drawList->els[0] = (DrawElement) {
- .x = state.x,
- .y = state.y,
- .w = 100,
- .h = 100,
- .r = 255,
- .g = 0,
- .b = 0,
- .a = 255,
+ // Goal
+ if (state->levelComplete) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * state->goalx + GRID_OFFSET_X,
+ .y = cellHeight * state->goaly,
+ .w = cellWidth,
+ .h = cellHeight,
+ .fill = {0, 255, 0, 63},
+ .border = {0, 255, 0, 255},
+ };
+ } else {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * state->goalx + GRID_OFFSET_X,
+ .y = cellHeight * state->goaly,
+ .w = cellWidth,
+ .h = cellHeight,
+ .fill = {255, 0, 0, 63},
+ .border = {255, 0, 0, 255},
+ };
+
+ if (state->need9) {
+ for (int i = 0; i < state->blues; i++) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * state->goalx + GRID_OFFSET_X + cellWidth / 3 * (i % 3),
+ .y = cellHeight * state->goaly + cellHeight / 3 * (i / 3),
+ .w = cellWidth / 3,
+ .h = cellHeight / 3,
+ .fill = {196, 255, 196, 255},
+ .border = {0, 200, 0, 255},
+ };
+ }
+ }
+ }
+
+ // Hover
+ if (ui->mousex >= GRID_OFFSET_X) {
+ int hoverx = (ui->mousex - GRID_OFFSET_X) * GRIDWIDTH / (ui->width - GRID_OFFSET_X);
+ int hovery = ui->mousey * GRIDHEIGHT / ui->height;
+
+ int cellx = ui->mousex - GRID_OFFSET_X - hoverx * cellWidth;
+ int celly = ui->mousey - hovery * cellHeight;
+
+ int hoverColor = getPlaceAction(
+ state->grid[hoverx + hovery * GRIDWIDTH],
+ cellx,
+ celly,
+ cellWidth,
+ cellHeight
+ );
+
+ if (hoverColor != EMPTY) {
+ for (int i = 0; i < MAX_PLACEABLE_CELLS; i++) {
+ if (state->placeableCells[i] == hoverColor) {
+ if (colorImages[hoverColor]) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * hoverx + GRID_OFFSET_X,
+ .y = cellHeight * hovery,
+ .w = cellWidth,
+ .h = cellHeight,
+ .image = {
+ .index = colorImages[hoverColor],
+ .opacity = 127,
+ },
+ };
+ } else {
+ int subCellWidth = cellWidth / 2;
+ int subCellHeight = cellHeight / 2;
+ for (int subx = 0; subx < 2; subx++) {
+ for (int suby = 0; suby < 2; suby++) {
+ Color fill = colors[hoverColor][subx + 2 * suby];
+ fill.a = 127;
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = cellWidth * hoverx + GRID_OFFSET_X + (subx * subCellWidth),
+ .y = cellHeight * hovery + (suby * subCellHeight),
+ .w = subCellWidth,
+ .h = subCellHeight,
+ .fill = fill,
+ };
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Side panel
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = 0,
+ .y = 0,
+ .w = GRID_OFFSET_X,
+ .h = ui->height,
+ .fill = {100, 100, 100, 255},
+ .border = {0, 0, 0, 255},
};
+ // render buttons
+ for (int i = 0; i < N_BUTTONS; i++) {
+ Color colour = {0, 0, 0, 255};
+ switch (state->buttonStates[i]) {
+ case BUTTON_STATE_IDLE:
+ colour = (Color) {0, 0, 0, 255};
+ break;
+ case BUTTON_STATE_HOVERED:
+ colour = (Color) {255, 255, 0, 255};
+ break;
+ case BUTTON_STATE_PRESSED:
+ colour = (Color) {255, 0, 0, 255};
+ break;
+ }
+ int image = IMAGE_NULL;
+ switch (i) {
+ case BUTTON_CONTINUE:
+ image = IMAGE_CONTINUE;
+ break;
+ case BUTTON_BACK:
+ image = IMAGE_EXIT;
+ break;
+ case BUTTON_RETRY:
+ image = IMAGE_RETRY;
+ break;
+ case BUTTON_PLAY:
+ image = state->playing ? IMAGE_PAUSE : IMAGE_PLAY;
+ break;
+ }
+ Color fill = {0};
+ if (i == BUTTON_CONTINUE && state->levelComplete) {
+ fill = (Color) {127, 255, 127, 200};
+ };
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = buttons[i].x,
+ .y = ui->height - buttons[i].y,
+ .w = buttons[i].w,
+ .h = buttons[i].h,
+ .fill = fill,
+ .image = (ImageRef) {
+ .index = image,
+ .opacity = 255,
+ },
+ };
+ }
+
+ // Placeable cells
+ for (int i = 0; i < MAX_PLACEABLE_CELLS; i++) {
+ if (state->placeableCells[i] == EMPTY) {
+ break;
+ }
+
+ if (colorImages[(int) state->placeableCells[i]]) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = BUTTON_SIZE / 2,
+ .y = BUTTON_SIZE / 2 + i * (BUTTON_SIZE + BUTTON_SPACING),
+ .w = BUTTON_SIZE,
+ .h = BUTTON_SIZE,
+ .image = {
+ .index = colorImages[(int) state->placeableCells[i]],
+ .opacity = 255,
+ },
+ };
+ } else {
+ for (int x = 0; x < 2; x++) {
+ for (int y = 0; y < 2; y++) {
+ drawList->els[drawList->len++] = (DrawElement) {
+ .x = BUTTON_SIZE / 2 + x * (BUTTON_SIZE / 2),
+ .y = BUTTON_SIZE / 2 + i * (BUTTON_SIZE + BUTTON_SPACING) + y * (BUTTON_SIZE / 2),
+ .w = BUTTON_SIZE / 2,
+ .h = BUTTON_SIZE / 2,
+ .fill = colors[(int) state->placeableCells[i]][x + 2 * y],
+ };
+ }
+ }
+ }
+ }
+
return drawList;
}
-static void update(Game *game, Arena a) {
+static void restart_level(Game* game) {
+ const int level = game->state.currentLevel;
+ xmemcpy(&game->state.grid, &levels[level].grid, sizeof(game->state.grid));
+ game->state.goalx = levels[level].goalx;
+ game->state.goaly = levels[level].goaly;
+ game->state.spawnerx = levels[level].spawnerx;
+ game->state.spawnery = levels[level].spawnery;
+ game->state.spawnerCount = 0;
+ game->state.playing = 0;
+ game->state.blues = 0;
+ game->state.need9 = levels[level].need9;
+ xmemcpy(&game->state.placeableCells, &levels[level].placeableCells, sizeof(game->state.placeableCells));
+}
+
+static int update(Game *game, uint64_t now, Arena a) {
+ const int offset_width = game->ui.width - GRID_OFFSET_X;
+
+ int tutorial = 0;
+
switch (game->input) {
- case INPUT_UP:
- game->state.y -= 20;
+ int x, y;
+ case INPUT_CLICK:
+ x = (game->ui.mousex - GRID_OFFSET_X) * GRIDWIDTH / offset_width;
+ y = game->ui.mousey * GRIDHEIGHT / game->ui.height;
+ if (game->ui.mousex >= GRID_OFFSET_X) {
+ float cellWidth = (float) (game->ui.width - GRID_OFFSET_X) / GRIDWIDTH;
+ float cellHeight = (float) game->ui.height / GRIDHEIGHT;
+ int cellx = game->ui.mousex - GRID_OFFSET_X - x * cellWidth;
+ int celly = game->ui.mousey - y * cellHeight;
+ // Keeping this around for testing purposes
+ // game->state.grid[x + y * GRIDWIDTH] = (game->state.grid[x + y * GRIDWIDTH] + 1) % (sizeof(colors) / sizeof(colors[0]));
+ char placed = getPlaceAction(
+ game->state.grid[x + y * GRIDWIDTH],
+ cellx,
+ celly,
+ cellWidth,
+ cellHeight
+ );
+
+ if (placed != EMPTY) {
+ for (int i = 0; i < MAX_PLACEABLE_CELLS; i++) {
+ if (game->state.placeableCells[i] == placed) {
+ game->state.grid[x + y * GRIDWIDTH] = placed;
+ for (int j = i; j < MAX_PLACEABLE_CELLS - 1; j++) {
+ game->state.placeableCells[j] = game->state.placeableCells[j + 1];
+ }
+ game->state.placeableCells[MAX_PLACEABLE_CELLS - 1] = EMPTY;
+ break;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < N_BUTTONS; i++) {
+ if (
+ game->ui.mousex > buttons[i].x && game->ui.mousex < buttons[i].x + buttons[i].w &&
+ game->ui.mousey > game->ui.height - buttons[i].y &&
+ game->ui.mousey < game->ui.height - buttons[i].y + buttons[i].h
+ ) {
+ // TODO - CLICK THINGS
+ //game->state.buttonStates[i] = BUTTON_STATE_PRESSED;
+ switch (i) {
+ case BUTTON_RETRY:
+ restart_level(game);
+ break;
+ case BUTTON_CONTINUE:
+ if (
+ !game->state.levelComplete ||
+ game->state.currentLevel + 1 >= sizeof(levels) / sizeof(levels[0])
+ ) {
+ break;
+ }
+ game->state.levelComplete = 0;
+ game->state.currentLevel++;
+ restart_level(game);
+ break;
+ case BUTTON_BACK:
+ tutorial = 1;
+ break;
+ case BUTTON_PLAY:
+ game->state.playing = !game->state.playing;
+ break;
+ }
+ }
+ }
break;
- case INPUT_DOWN:
- game->state.y += 20;
+ case INPUT_RCLICK:
+ if (game->ui.mousex > GRID_OFFSET_X) {
+ x = (game->ui.mousex - GRID_OFFSET_X) * GRIDWIDTH / (game->ui.width - GRID_OFFSET_X);
+ y = game->ui.mousey * GRIDHEIGHT / game->ui.height;
+
+ if (game->state.grid[x + y * GRIDWIDTH] != BLACK) {
+ break;
+ }
+
+ for (int i = 0; i < MAX_PLACEABLE_CELLS; i++) {
+ if (game->state.placeableCells[i] == YELLOW) {
+ game->state.grid[x + y * GRIDWIDTH] = YELLOW;
+ for (int j = i; j < MAX_PLACEABLE_CELLS - 1; j++) {
+ game->state.placeableCells[j] = game->state.placeableCells[j + 1];
+ }
+ game->state.placeableCells[MAX_PLACEABLE_CELLS - 1] = EMPTY;
+ break;
+ }
+ }
+ }
break;
- case INPUT_LEFT:
- game->state.x -= 20;
+ case INPUT_PAUSE_PLAY:
+ game->state.playing = !game->state.playing;
break;
- case INPUT_RIGHT:
- game->state.x += 20;
+ case INPUT_RESTART:
+ restart_level(game);
break;
default:
break;
}
+
+ if (game->state.playing && game->state.lastTick + TICK_LENGTH <= now) {
+ game->state.lastTick = now;
+
+ tick(game, a);
+ }
+
+ return tutorial;
}
#if SDL
#include <SDL3/SDL.h>
+typedef struct {
+ int width, height;
+ Color colors[16];
+ const char *pixels;
+} Image;
+
+#include "../build/images.c"
+
+SDL_Texture *textures[sizeof(images) / sizeof(images[0])];
+
+#include "../build/music.c"
+
+SDL_AudioStream *stream;
+
int main(int argc, char **argv) {
(void) argc;
(void) argv;
@@ -109,76 +531,138 @@ int main(int argc, char **argv) {
};
Game *game = new(&a, 1, Game);
- game->state = (State) {
- .x = 100,
- .y = 100,
- };
+ game->state.currentLevel = 0;
+ restart_level(game);
game->ui = (UI) {
.width = 640,
.height = 480,
+ .mousex = 0,
+ .mousey = 0,
};
+ for (int i = 0; i < N_BUTTONS; i++) {
+ game->state.buttonStates[i] = BUTTON_STATE_IDLE;
+ }
- SDL_Init(SDL_INIT_VIDEO);
+ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *w = SDL_CreateWindow(
"LDJam 57",
game->ui.width,
game->ui.height,
- 0
+ SDL_WINDOW_RESIZABLE
);
SDL_PropertiesID renderProps = SDL_CreateProperties();
SDL_SetPointerProperty(renderProps, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, w);
SDL_SetNumberProperty(renderProps, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 1);
SDL_Renderer *r = SDL_CreateRendererWithProperties(renderProps);
SDL_DestroyProperties(renderProps);
+ SDL_SetRenderDrawBlendMode(r, SDL_BLENDMODE_BLEND);
+
+ for (int j = 1; j < (int) (sizeof(images) / sizeof(images[0])); j++) {
+ textures[j] = SDL_CreateTexture(
+ r,
+ SDL_PIXELFORMAT_ABGR8888,
+ SDL_TEXTUREACCESS_STATIC,
+ images[j].width,
+ images[j].height
+ );
+ SDL_SetTextureScaleMode(textures[j], SDL_SCALEMODE_NEAREST);
+ Arena scratch = a;
+ Color *pixels = new(&scratch, images[j].width * images[j].height, Color);
+ for (int i = 0; i < images[j].width * images[j].height; i++) {
+ pixels[i] = images[j].colors[(int) images[j].pixels[i]];
+ }
+ SDL_UpdateTexture(textures[j], NULL, pixels, images[j].width * 4);
+ }
+
+ SDL_AudioSpec audioSpec = {
+ .format = SDL_AUDIO_S16LE,
+ .channels = 2,
+ .freq = 48000,
+ };
+ stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audioSpec, NULL, NULL);
+ SDL_PutAudioStreamData(stream, musicBytes, sizeof(musicBytes));
+ SDL_ResumeAudioStreamDevice(stream);
for (;;) {
+ uint64_t now = SDL_GetTicks();
game->input = INPUT_NONE;
SDL_Event e = {0};
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_EVENT_QUIT:
return 0;
+ case SDL_EVENT_MOUSE_BUTTON_DOWN:
+ game->ui.mousex = (int) e.button.x;
+ game->ui.mousey = (int) e.button.y;
+ if (e.button.button == 1) {
+ game->input = INPUT_CLICK;
+ } else if (e.button.button == 3) {
+ game->input = INPUT_RCLICK;
+ }
+ break;
+ case SDL_EVENT_MOUSE_MOTION:
+ game->ui.mousex = (int) e.motion.x;
+ game->ui.mousey = (int) e.motion.y;
+ game->input = INPUT_MOVE;
+ break;
case SDL_EVENT_KEY_DOWN:
switch (e.key.key) {
- case 'w':
- game->input = INPUT_UP;
- break;
- case 'a':
- game->input = INPUT_LEFT;
+ case SDLK_SPACE:
+ game->input = INPUT_PAUSE_PLAY;
break;
- case 's':
- game->input = INPUT_DOWN;
- break;
- case 'd':
- game->input = INPUT_RIGHT;
+ case SDLK_R:
+ game->input = INPUT_RESTART;
break;
}
break;
+ case SDL_EVENT_WINDOW_RESIZED:
+ SDL_GetWindowSize(w, &game->ui.width, &game->ui.height);
+ break;
}
}
Arena scratch = a;
- DrawList *drawList = render(game->state, &game->ui, &scratch);
+ DrawList *drawList = render(&game->state, &game->ui, &scratch);
SDL_SetRenderDrawColor(r, 0, 0, 0, 255);
SDL_RenderFillRect(r, NULL);
+
for (int i = 0; i < drawList->len; i++) {
- SDL_SetRenderDrawColor(
- r,
- drawList->els[i].r,
- drawList->els[i].g,
- drawList->els[i].b,
- drawList->els[i].a
- );
SDL_FRect rect = {
.x = (float) drawList->els[i].x,
.y = (float) drawList->els[i].y,
.w = (float) drawList->els[i].w,
.h = (float) drawList->els[i].h
};
+
+ SDL_SetRenderDrawColor(
+ r,
+ drawList->els[i].fill.r,
+ drawList->els[i].fill.g,
+ drawList->els[i].fill.b,
+ drawList->els[i].fill.a
+ );
SDL_RenderFillRect(r, &rect);
+
+ SDL_SetRenderDrawColor(
+ r,
+ drawList->els[i].border.r,
+ drawList->els[i].border.g,
+ drawList->els[i].border.b,
+ drawList->els[i].border.a
+ );
+ SDL_RenderRect(r, &rect);
+
+ if (drawList->els[i].image.index != 0) {
+ SDL_SetTextureAlphaMod(textures[(int) drawList->els[i].image.index], drawList->els[i].image.opacity);
+ SDL_RenderTexture(r, textures[(int) drawList->els[i].image.index], NULL, &rect);
+ }
}
- update(game, a);
+ update(game, now, a);
+
+ if (SDL_GetAudioStreamQueued(stream) < (int) sizeof(musicBytes) / 8) {
+ SDL_PutAudioStreamData(stream, musicBytes, sizeof(musicBytes));
+ }
SDL_RenderPresent(r);
}
@@ -198,24 +682,32 @@ void game_init(void) {
perm.end = heap + MEM_SIZE;
game = new(&perm, 1, Game);
- game->state = (State) {
- .x = 100,
- .y = 100,
- };
+ game->state.currentLevel = 0;
+ restart_level(game);
+
+ for (int i = 0; i < N_BUTTONS; i++) {
+ game->state.buttonStates[i] = BUTTON_STATE_IDLE;
+ }
}
__attribute((export_name("game_render")))
-DrawList *game_render(int width, int height) {
+DrawList *game_render(int width, int height, int mousex, int mousey) {
game->ui.width = width;
game->ui.height = height;
+ game->ui.mousex = mousex;
+ game->ui.mousey = mousey;
Arena scratch = perm;
- return render(game->state, &game->ui, &scratch);
+ return render(&game->state, &game->ui, &scratch);
}
__attribute((export_name("game_update")))
-void game_update(int input) {
+int game_update(int input, int mousex, int mousey, int now) {
game->input = input;
- update(game, perm);
+ game->ui.mousex = mousex;
+ game->ui.mousey = mousey;
+ return update(game, now, perm);
}
#endif
+
+#endif