summary refs log tree commit diff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c290
1 files changed, 208 insertions, 82 deletions
diff --git a/src/main.c b/src/main.c
index 2d3e89d..c48deef 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,6 +19,8 @@
 
 SDL_Window *window = NULL;
 SDL_Renderer *renderer = NULL;
+enum game_state game_state = STATE_PLAYING;
+char *game_next_level;
 
 #define WINDOW_WIDTH 160
 #define WINDOW_HEIGHT 90
@@ -34,13 +36,134 @@ SDL_Scancode keybinds[] = {
 	SDL_SCANCODE_S,
 };
 
-struct entity player[1] = {0};
+struct entities entities = {{{0}}, {{0}}, 0, {{0}}, 0}, next_entities = {{{0}}, {{0}}, 0, {{0}}, 0};
 
-struct entity *player_new(void);
-int player_property(struct entity *const restrict entity, char const *const restrict property, char const *const restrict value);
+void *player_new(struct entities *entities);
+int player_property(void *const restrict entity, char const *const restrict property, char const *const restrict value);
 
 void funs_init(void);
 
+void entities_free(struct entities *entities) {
+	for (int i = 0, e = 0; i < 64 && e < entities->enemies; i++) {
+		if (entities->enemy[i].state) {
+			e++;
+			if (entities->enemy[i].free != NULL) {
+				entities->enemy[i].free(entities->enemy + i);
+			}
+		}
+	}
+	entities->enemies = 0;
+	#if 0
+	for (int i = 0; i < entities.warps; i++) {
+		entities.warp[i].update(entities.warp + i);
+	}
+	#endif
+	entities->warps = 0;
+}
+
+int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes) {
+	entities->enemies = 0;
+	entities->warps = 0;
+	data += input_bytes;
+	size -= input_bytes;
+	while (size) {
+		size_t len;
+		if ((len = strnlen(data, size)) == size) {
+			return 1;
+		}
+		char *name = data;
+		struct funs fun = res_get_fun(name);
+		data += len + 1;
+		size -= len + 1;
+		if (fun.newfun) {
+			struct entity *entity = fun.newfun(&next_entities);
+			while (1) {
+				if ((len = strnlen(data, size)) == size) {
+					return 1;
+				} else if (len == 0) {
+					data++;
+					size--;
+					break;
+				}
+				char *key = data;
+				data += len + 1;
+				size -= len + 1;
+				if ((len = strnlen(data, size)) == size) {
+					return 1;
+				}
+				char *value = data;
+				data += len + 1;
+				size -= len + 1;
+				if (fun.setfun(entity, key, value)) {
+					puts(key); puts(value);
+					return 1;
+				}
+			}
+		} else {
+			fprintf(stderr, "warn: unknown entity %s\n", name);
+			while (1) {
+				if ((len = strnlen(data, size)) == size) {
+					return 1;
+				} else if (len == 0) {
+					data++;
+					size--;
+					break;
+				}
+				data += len + 1;
+				size -= len + 1;
+				if ((len = strnlen(data, size)) == size) {
+					return 1;
+				}
+				data += len + 1;
+				size -= len + 1;
+			}
+		}
+	}
+	return 0;
+}
+
+int game_update(void) {
+	if (entities.player[0].update(entities.player)) {
+		return 1;
+	}
+	
+	for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) {
+		if (entities.enemy[i].state) {
+			e++;
+			entities.enemy[i].update(entities.enemy + i);
+		}
+	}
+	
+	for (int i = 0; i < entities.warps; i++) {
+		entities.warp[i].update(entities.warp + i);
+	}
+	
+	return 0;
+}
+
+void game_render(SDL_Texture *framebuffer, int x, int y) {
+	SDL_SetRenderTarget(renderer, framebuffer);
+	tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+	entities.player[0].draw(entities.player, x, y);
+	for (int i = 0, e = 0; i < 64 && e < entities.enemies; i++) {
+		if (entities.enemy[i].state) {
+			e++;
+			entities.enemy[i].draw(entities.enemy + i, x, y);
+		}
+	}
+	tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+	//SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
+}
+
+void game_render_flush(SDL_Texture *framebuffer) {
+	SDL_SetRenderTarget(renderer, NULL);
+	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+	SDL_RenderClear(renderer);
+	SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+	// then we wait for the next video frame 
+	SDL_RenderPresent(renderer);
+}
+
 int main(int const argc, char *const *const argv) {
 	struct option opts[] = {
 		{"help",       0, NULL, 'h'},
@@ -176,60 +299,19 @@ int main(int const argc, char *const *const argv) {
 				optind++;
 			}
 		}
-		struct blob map = res_get_map("untitled");
-		tilemap = tilemap_load(map.data, map.size);
-		char *a = (char *) map.data + tilemap->input_bytes;
-		map.size -= tilemap->input_bytes;
-		while (map.size) {
-			size_t len;
-			if ((len = strnlen(a, map.size)) == map.size) {
-				return 1; // hack
-			}
-			char *name = a;
-			puts(name);
-			struct funs fun = res_get_fun(name);
-			a += len + 1;
-			map.size -= len + 1;
-			if (fun.newfun) {
-				struct entity *entity = fun.newfun();
-				while (1) {
-					if ((len = strnlen(a, map.size)) == map.size) {
-						return 1; // hack
-					} else if (len == 0) {
-						a++;
-						map.size--;
-						break;
-					}
-					char *key = a;
-					a += len + 1;
-					map.size -= len + 1;
-					if ((len = strnlen(a, map.size)) == map.size) {
-						return 1; // hack
-					}
-					char *value = a;
-					a += len + 1;
-					map.size -= len + 1;
-					if (fun.setfun(entity, key, value)) {
-						return 1; // hack
-					}
-				}
-			} else {
-				while (1) { // hack
-					if ((len = strnlen(a, map.size)) == map.size) { // hack
-						return 1; // hack
-					} else if (len == 0) {
-						a++;
-						map.size--;
-						break;
-					}
-					a += len + 1;
-					map.size -= len + 1;
-				}
-			}
+
+		struct blob blob = res_get_map("untitled");
+		next_tilemap = tilemap_load(blob.data, blob.size);
+		if (next_tilemap == NULL) {
+			fputs("failed to load initial tilemap\n", stderr);
+			goto end;
 		}
-		//memmem(map.data + tilemap->byte_count, map.size - tilemap->byte_count, (char []) {0, 0}, 2);
-		printf("load_tilemap %p\n", (void *) tilemap);
-		SDL_SetRenderTarget(renderer, NULL);
+		if (entities_load(&entities, blob.data, blob.size, next_tilemap->input_bytes)) {
+			tilemap_free(next_tilemap);
+			fputs("failed to load initial tilemap\n", stderr);
+			goto end;
+		}
+		tilemap = next_tilemap;
 	}
 
 	/* unsigned error; // identical variable is declared higher up */
@@ -251,10 +333,11 @@ int main(int const argc, char *const *const argv) {
 
 	SDL_ShowWindow(window);
 	
-	int x = 0, y = 0;
-	player_new();
-	player_property(player, "x", "40");
-	player_property(player, "y", "64");
+	int x = 0, y = 0, fade = 0;
+	player_new(&next_entities);
+	player_property(next_entities.player, "x", "40");
+	player_property(next_entities.player, "y", "64");
+	memcpy(&entities, &next_entities, sizeof (entities));
 	while (1) {
 		SDL_Event evt;
 		while (SDL_PollEvent(&evt)) {
@@ -352,29 +435,72 @@ int main(int const argc, char *const *const argv) {
 			}
 		}
 
-		//SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
-		if (player[0].update(player)) {
-			break; // TODO: game over state
+		switch (game_state) {
+			case STATE_PLAYING:
+				//SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
+				if (game_update()) {
+					goto end; // TODO: game over state
+				}
+				
+				x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+				y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+				if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+				if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+				
+				game_render(framebuffer, x, y);
+				game_render_flush(framebuffer);
+				break;
+
+			case STATE_FADE_IN:
+				fade += 15;
+				SDL_SetRenderTarget(renderer, NULL);
+				SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+				SDL_RenderClear(renderer);
+				SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+				SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade);
+				SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+				SDL_RenderPresent(renderer);
+				if (fade == 255) {
+					struct blob blob = res_get_map(game_next_level);
+					next_tilemap = tilemap_load(blob.data, blob.size);
+					if (next_tilemap != NULL) {
+						if (entities_load(&next_entities, blob.data, blob.size, next_tilemap->input_bytes)) {
+							tilemap_free(next_tilemap);
+						} else {
+							tilemap_free(tilemap);
+							tilemap = next_tilemap;
+							entities_free(&entities);
+							memcpy(&entities, &next_entities, sizeof (entities));
+						}
+					}
+					game_state = STATE_FADE_OUT;
+
+					x = (entities.player[0].x / 16) - (WINDOW_WIDTH / 2);
+					y = (entities.player[0].y / 16) - (WINDOW_HEIGHT / 2);
+					if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
+					if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
+					
+					game_render(framebuffer, x, y);
+					SDL_SetRenderTarget(renderer, NULL);
+					SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+					SDL_RenderClear(renderer);
+				}
+				break;
+			
+			case STATE_FADE_OUT:
+				fade -= 15;
+				SDL_SetRenderTarget(renderer, NULL);
+				SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+				SDL_RenderClear(renderer);
+				SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+				SDL_SetRenderDrawColor(renderer, 0, 0, 0, fade);
+				SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
+				SDL_RenderPresent(renderer);
+				if (fade == 0) {
+					game_state = STATE_PLAYING;
+				}
+				break;
 		}
-		
-		//x += input_right(input_now) - input_left(input_now);
-		//y += input_down(input_now) - input_up(input_now);
-		x = (player[0].x / 16) - (WINDOW_WIDTH / 2);
-		y = (player[0].y / 16) - (WINDOW_HEIGHT / 2);
-		if (x < 0) {x = 0;} else if (x + WINDOW_WIDTH > tilemap->width * 8) {x = tilemap->width * 8 - WINDOW_WIDTH;}
-		if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
-		
-		SDL_SetRenderTarget(renderer, framebuffer);
-		tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
-		player[0].draw(player, x, y);
-		tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
-		//SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
-		SDL_SetRenderTarget(renderer, NULL);
-		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
-		SDL_RenderClear(renderer);
-		SDL_RenderCopy(renderer, framebuffer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
-		// then we wait for the next video frame 
-		SDL_RenderPresent(renderer);
 	}
 	
 	end: