summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile2
-rw-r--r--src/entity.h53
-rw-r--r--src/main.c66
-rw-r--r--src/main.h6
-rw-r--r--src/player.c114
-rw-r--r--src/warp.c4
6 files changed, 211 insertions, 34 deletions
diff --git a/GNUmakefile b/GNUmakefile
index f16eaa2..8b08ac0 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -2,7 +2,7 @@
 
 export MKDIR ?= mkdir -p
 
-libs := SDL2 z
+libs := SDL2 m z
 
 CFLAGS ?= -Wall -Wpedantic -g -Og
 cflags := ${CFLAGS}
diff --git a/src/entity.h b/src/entity.h
index fe76feb..0166bdc 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -5,23 +5,29 @@
 #define from_fixed(a) (a / 16)
 #define to_fixed(a) (a * 16)
 
+struct vec2 {
+	signed x, y;
+};
+
+struct hitbox {
+	unsigned left, right, top, bottom;
+};
+
+struct anim {
+	unsigned frame;
+	SDL_Rect rect;
+	unsigned length;
+};
+
 struct entity {
 	int (*update)(struct entity *self);
 	int (*hurt)(struct entity *self, int damage);
 	int (*draw)(struct entity *self, int camx, int camy);
 	void (*free)(struct entity *self);
 	int x, y; // unsigned results in a bunch of weird edge cases
-	struct velocity {
-		signed x, y;
-	} velocity;
-	struct hitbox {
-		unsigned left, right, top, bottom;
-	} hitbox;
-	struct anim {
-		unsigned frame;
-		SDL_Rect rect;
-		unsigned length;
-	} anim;
+	struct vec2 velocity;
+	struct hitbox hitbox;
+	struct anim anim;
 	unsigned state;
 	int hp;
 	int timer;
@@ -40,3 +46,28 @@ struct warp {
 	unsigned timer;
 	void *ext;
 };
+
+struct projectile {
+	int (*update)(struct projectile *self);
+	int (*draw)(struct projectile *self, int camx, int camy);
+	void (*free)(struct projectile *self);
+	int x, y; // unsigned results in a bunch of weird edge cases
+	struct vec2 velocity;
+	struct hitbox hitbox;
+	struct anim anim;
+	unsigned state;
+	int hp;
+	int timer;
+	int iframes;
+	signed facing;
+	void *texture;
+	void *ext;
+};
+
+struct particle {
+	int x, y;
+	struct vec2 velocity;
+	struct vec2 acceleration;
+	SDL_Rect rect;
+	int hp;
+};
diff --git a/src/main.c b/src/main.c
index c48deef..d5f6504 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "input.h"
 #include "loader.h"
@@ -22,11 +23,13 @@ SDL_Renderer *renderer = NULL;
 enum game_state game_state = STATE_PLAYING;
 char *game_next_level;
 
+static void *particle_tex = NULL;
+
 #define WINDOW_WIDTH 160
 #define WINDOW_HEIGHT 90
 #define INIT_SUBSYSTEMS SDL_INIT_VIDEO
 
-unsigned input_now = 0;
+unsigned input_pressed = 0, input_held = 0;
 SDL_Scancode keybinds[] = {
 	SDL_SCANCODE_UP,
 	SDL_SCANCODE_DOWN,
@@ -64,6 +67,8 @@ void entities_free(struct entities *entities) {
 int entities_load(struct entities *entities, char *data, size_t size, size_t input_bytes) {
 	entities->enemies = 0;
 	entities->warps = 0;
+	entities->projectiles = 0;
+	entities->particles = 0;
 	data += input_bytes;
 	size -= input_bytes;
 	while (size) {
@@ -138,6 +143,31 @@ int game_update(void) {
 		entities.warp[i].update(entities.warp + i);
 	}
 	
+	for (int i = 0, e = 0; i < 64 && e < entities.projectiles; i++) {
+		if (entities.projectile[i].state) {
+			e++;
+			if (entities.projectile[i].update(entities.projectile + i)) {
+				entities.projectiles--;
+				if (entities.projectile + i != entities.projectile + entities.projectiles) {
+					memcpy(entities.projectile + i, entities.projectile + entities.projectiles, sizeof (struct projectile));
+				}
+				continue;
+			}
+		}
+	}
+
+	for (int i = 0; i < entities.particles; i++) {
+		if (entities.particle[i].hp-- == 0) {
+			entities.particles--;
+			if (entities.particle + i != entities.particle + entities.particles) {
+				memcpy(entities.particle + i, entities.particle + entities.particles, sizeof (struct particle));
+			}
+			continue;
+		}
+		entities.particle[i].x += (entities.particle[i].velocity.x += entities.particle[i].acceleration.x);
+		entities.particle[i].y += (entities.particle[i].velocity.y += entities.particle[i].acceleration.y);
+	}
+	
 	return 0;
 }
 
@@ -151,8 +181,17 @@ void game_render(SDL_Texture *framebuffer, int x, int y) {
 			entities.enemy[i].draw(entities.enemy + i, x, y);
 		}
 	}
+	for (int i = 0, e = 0; i < 64 && e < entities.projectiles; i++) {
+		if (entities.projectile[i].state) {
+			e++;
+			entities.projectile[i].draw(entities.projectile + i, x, y);
+		}
+	}
+	for (int i = 0; i < entities.particles; i++) {
+		struct particle *self = entities.particle + i;
+		SDL_RenderCopy(renderer, particle_tex, &self->rect, &(SDL_Rect) {from_fixed(self->x) - x, from_fixed(self->y) - y, self->rect.w, self->rect.h});
+	}
 	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) {
@@ -174,8 +213,8 @@ int main(int const argc, char *const *const argv) {
 		{"border",     2, NULL, 'b'},
 		{NULL,         0, NULL,  0 },
 	};
-	int opt, li;
-	unsigned scale = 0, flags = 0, error = 0;
+	int opt, li, scale = 0;
+	unsigned flags = 0, error = 0;
 	while ((opt = getopt_long(argc, argv, "h", opts, &li)) != -1) {
 		switch (opt) {
 			case 'h':
@@ -199,9 +238,9 @@ int main(int const argc, char *const *const argv) {
 			
 			case 'f':
 				if (optarg == NULL || strcmp(optarg, "true") == 0) {
-					flags |= SDL_WINDOW_FULLSCREEN;
+					flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 				} else if (strcmp(optarg, "false") == 0) {
-					flags &= ~SDL_WINDOW_FULLSCREEN;
+					flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
 				} else {
 					fprintf(stderr, "%s=%s -- expected 'true' or 'false'\n", opts[li].name, optarg);
 					error = 1;
@@ -243,7 +282,7 @@ int main(int const argc, char *const *const argv) {
 		return EXIT_FAILURE;
 	}
 	SDL_StopTextInput();
-	if (scale == 0) {
+	if (scale <= 0) {
 		SDL_DisplayMode dm;
 		if (SDL_GetDesktopDisplayMode(0, &dm) != 0) {
 			SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "couldnt get desktop size", SDL_GetError(), NULL);
@@ -299,6 +338,8 @@ int main(int const argc, char *const *const argv) {
 				optind++;
 			}
 		}
+		
+		particle_tex = res_get_texture("particles").data;
 
 		struct blob blob = res_get_map("untitled");
 		next_tilemap = tilemap_load(blob.data, blob.size);
@@ -339,6 +380,7 @@ int main(int const argc, char *const *const argv) {
 	player_property(next_entities.player, "y", "64");
 	memcpy(&entities, &next_entities, sizeof (entities));
 	while (1) {
+		input_pressed = input_held;
 		SDL_Event evt;
 		while (SDL_PollEvent(&evt)) {
 			switch (evt.type) {
@@ -355,16 +397,16 @@ int main(int const argc, char *const *const argv) {
 						goto end;
 					}
 					
-					//static_assert(INPUT_LENGTH <= sizeof(input_now) * CHAR_BIT); // if this trips up, scope creep happened
+					//static_assert(INPUT_LENGTH <= sizeof(input_held) * CHAR_BIT); // if this trips up, scope creep happened
 					for (unsigned key = 0, bit = 1; key < INPUT_LENGTH; key++, bit <<= 1) {
 						if (evt.key.keysym.scancode == keybinds[key]) {
 							if (evt.key.state == SDL_PRESSED)
-								input_now |= bit;
+								input_held |= bit;
 							else
-								input_now &= ~bit;
+								input_held &= ~bit;
 						}
 					}
-					//fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_now);
+					//fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_held);
 					break;
 				case SDL_MOUSEMOTION: // the cursor moves
 					//fprintf(stderr, "mouse at %4i %4i\n", evt.motion.x, evt.motion.y);
@@ -434,6 +476,8 @@ int main(int const argc, char *const *const argv) {
 					fprintf(stderr, "unknown event type %i\n", evt.type);
 			}
 		}
+		input_pressed = ~input_pressed & input_held;
+		//fprintf(stderr, "input: %0*b\n", INPUT_LENGTH, input_pressed);
 
 		switch (game_state) {
 			case STATE_PLAYING:
diff --git a/src/main.h b/src/main.h
index d743ce7..ef214bb 100644
--- a/src/main.h
+++ b/src/main.h
@@ -5,14 +5,18 @@
 extern SDL_Window *window;
 extern SDL_Renderer *renderer;
 
-extern unsigned input_now;
+extern unsigned input_pressed, input_held;
 
 extern struct entities {
 	struct entity player[1];
 	struct entity enemy[64];
 	unsigned enemies;
+	struct projectile projectile[64];
+	unsigned projectiles;
 	struct warp warp[16];
 	unsigned warps;
+	struct particle particle[64];
+	unsigned particles;
 } entities, next_entities;
 
 extern enum game_state {
diff --git a/src/player.c b/src/player.c
index 0f0025e..a6fa86d 100644
--- a/src/player.c
+++ b/src/player.c
@@ -4,6 +4,7 @@
 #include "input.h"
 #include "tilemap.h"
 #include <stdbool.h>
+#include <math.h>
 
 #define SIZE 4
 #define ACCELERATION 1
@@ -44,13 +45,50 @@ struct anim player_anims[] = {
 	{PLAYER_A_FALL2, {48, 0, 16, 16}, 15},
 };
 
+static int slash_update(struct projectile *self) {
+	self->x += self->velocity.x;
+	self->y += self->velocity.y;
+	self->hp--;
+	#if 0
+		struct particle *part = entities.particle + entities.particles;
+		part->x = self->x + to_fixed(self->facing >= 0? sin(self->hp): -sin(self->hp)) * 6;
+		part->y = self->y - to_fixed(cos(self->hp)) * 4;
+		part->velocity = (struct vec2) {0, 0};
+		part->rect = (SDL_Rect) {0, 0, 4, 4};
+		part->acceleration = (struct vec2) {0, 0};
+		part->hp = 5;
+		entities.particles++;
+	#endif
+	if (self->hp == 0) {
+		return 1;
+		self->state = 0;
+	}
+	return 0;
+}
+
+static int slash_draw(struct projectile *self, int camX, int camY) {
+	//SDL_Rect rect = self->anim.rect;
+	//SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+	//SDL_RenderFillRect(renderer, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+	int const x = from_fixed(self->x) - camX, y = from_fixed(self->y) - camY;
+	SDL_Vertex vertices[3] = {
+		{.position = {x + from_fixed(self->velocity.x) + ((self->facing >= 0)? sin(self->hp - 1): -sin(self->hp - 1)) * 8, y - cos(self->hp - 1) * 6}, .color = {255, 127, 0, 255}},
+		{.position = {x + ((self->facing >= 0)? sin(self->hp + 0): -sin(self->hp + 0)) * 8, y - cos(self->hp + 0) * 6}, .color = {255, 127, 0, 255}},
+		{.position = {x - from_fixed(self->velocity.x) + ((self->facing >= 0)? sin(self->hp + 1): -sin(self->hp + 1)) * 8, y - cos(self->hp + 1) * 6}, .color = {255, 127, 0, 255}},
+	};
+	SDL_RenderGeometry(renderer, NULL, vertices, 3, NULL, 0);
+	return 0;
+}
+
+static void slash_free(struct projectile *self) {}
+
 static collision_T collide(struct entity *self) {
 	return tilemap_area(tilemap, from_fixed(self->x) - SIZE / 2, from_fixed(self->y) - SIZE, from_fixed(self->x) + SIZE / 2, from_fixed(self->y));
 }
 
 static int move(struct entity *self) {
 	int on_ground = false;
-	int dx = (input_right(input_now) - input_left(input_now)) * ACCELERATION;
+	int dx = (input_right(input_held) - input_left(input_held)) * ACCELERATION;
 	self->velocity.x += dx;
 	// deaccel
 	if (dx == 0) {
@@ -114,6 +152,32 @@ static int move(struct entity *self) {
 	return on_ground;
 }
 
+static void attack(struct entity *self) {
+	if (!input_s(input_pressed)) {
+		return;
+	}
+	entities.projectile[entities.projectiles] = (struct projectile) {
+		.update = slash_update,
+		.draw = slash_draw,
+		.free = slash_free,
+		.x = self->x + to_fixed(self->facing) * 4, .y = self->y - to_fixed(3),
+		.velocity = (struct vec2) {self->velocity.x, 0},
+		.hitbox = {
+			0, 0, 0, 0,
+		},
+		.state = PLAYER_IDLE,
+		.hp = 4,
+		.timer = 0,
+		.facing = self->facing,
+		.iframes = 0,
+		.texture = NULL,
+		.ext = NULL,
+	};
+	//anim(entities->projectile + entities->projectiles, ENEMY_A_IDLE);
+	//entities->projectile[entities->projectiles].texture = res_get_texture("fywi").data;
+	entities.projectiles++;
+}
+
 static void anim(struct entity *self, unsigned anim) {
 	self->anim = player_anims[anim];
 }
@@ -130,36 +194,47 @@ static int player_update(struct entity *self) {
 				anim(self, PLAYER_A_FALL);
 				self->state = PLAYER_FALL;
 			}
-			if (input_right(input_now) - input_left(input_now)) {
+			if (input_right(input_held) - input_left(input_held)) {
 				anim(self, PLAYER_A_WALK);
 				self->state = PLAYER_WALK;
 			}
-			if (input_a(input_now)) {
+			if (input_a(input_held)) {
 				self->velocity.y = -JUMP;
 				anim(self, PLAYER_A_JUMP);
 				self->state = PLAYER_JUMP;
 			}
+			attack(self);
 			break;
 
-		case PLAYER_WALK:
+		case PLAYER_WALK:;
+			struct particle *part = entities.particle + entities.particles;
+			part->x = self->x - to_fixed(self->facing) * 3 - to_fixed(1);
+			part->y = self->y - 2;
+			part->velocity = (struct vec2) {-self->velocity.x, -8};
+			part->rect = (SDL_Rect) {0, 0, 4, 4};
+			part->acceleration = (struct vec2) {0, 1};
+			part->hp = 5;
+			entities.particles++;
+
 			if (move(self) == false) {
 				self->velocity.y = 0;
 				anim(self, PLAYER_A_FALL);
 				self->state = PLAYER_FALL;
 			}
-			if (!(input_right(input_now) - input_left(input_now))) {
+			if (!(input_right(input_held) - input_left(input_held))) {
 				anim(self, PLAYER_A_IDLE);
 				self->state = PLAYER_IDLE;
 			}
-			if (input_a(input_now)) {
+			if (input_a(input_held)) {
 				self->velocity.y = -JUMP;
 				anim(self, PLAYER_A_JUMP);
 				self->state = PLAYER_JUMP;
 			}
+			attack(self);
 			break;
 		
 		case PLAYER_JUMP:
-			if (!input_a(input_now)) {
+			if (!input_a(input_held)) {
 				self->velocity.y /= 2;
 				anim(self, PLAYER_A_FALL);
 				self->state = PLAYER_FALL;
@@ -174,10 +249,21 @@ static int player_update(struct entity *self) {
 			}
 			break;
 		
-		case PLAYER_FALL:
+		case PLAYER_FALL:;
+			int yy = self->velocity.y;
 			if (move(self) == true) {
 				anim(self, PLAYER_A_IDLE);
 				self->state = PLAYER_IDLE;
+				for (int x = -2; x <= 2; x++) {
+					struct particle *part = entities.particle + entities.particles;
+					part->x = self->x;
+					part->y = self->y;
+					part->velocity = (struct vec2) {x * 5, -yy / 4 - 8};
+					part->rect = (SDL_Rect) {0, 0, 4, 4};
+					part->acceleration = (struct vec2) {0, 1};
+					part->hp = yy / 2;
+					entities.particles++;
+				}
 			}
 			break;
 	}
@@ -195,6 +281,18 @@ static int player_hurt(struct entity *self, int damage) {
 	if (self->iframes == 0) {
 		self->hp -= damage;
 		self->iframes = 60;
+		for (int x = -1; x <= 1; x += 2) {
+			for (int y = -1; y <= 1; y += 2) {
+				struct particle *part = entities.particle + entities.particles;
+				part->x = self->x;
+				part->y = self->y;
+				part->velocity = (struct vec2) {to_fixed(x), to_fixed(y) - 8};
+				part->rect = (SDL_Rect) {0, 0, 4, 4};
+				part->acceleration = (struct vec2) {0, 1};
+				part->hp = 30;
+				entities.particles++;
+			}
+		}
 	}
 	return 0;
 }
diff --git a/src/warp.c b/src/warp.c
index f36b716..3556ef3 100644
--- a/src/warp.c
+++ b/src/warp.c
@@ -15,8 +15,8 @@ static int warp_update(struct warp *self) {
 		}
 		game_next_level = self->ext;
 		memcpy(next_entities.player, entities.player, sizeof (entities.player));
-		next_entities.player[0].x = self->tox * 16;
-		next_entities.player[0].y = self->toy * 16;
+		next_entities.player[0].x = to_fixed(self->tox);
+		next_entities.player[0].y = to_fixed(self->toy);
 		game_state = STATE_FADE_IN;
 		self->ext = NULL;
 		return 0;