summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/funsinit.c3
-rw-r--r--src/walker.c329
2 files changed, 332 insertions, 0 deletions
diff --git a/src/funsinit.c b/src/funsinit.c
index 25ba630..264a653 100644
--- a/src/funsinit.c
+++ b/src/funsinit.c
@@ -2,9 +2,12 @@
 #include "loader.h"
 #include "main.h"
 
+void *walker_new(struct entities *entities);
+int walker_property(void *const restrict entity, char const *const restrict property, char const *const restrict value);
 void *warp_new(struct entities *entities);
 int warp_property(void *const restrict entity, char const *const restrict property, char const *const restrict value);
 
 void funs_init(void) {
+	res_push_fun(walker_new, walker_property, "walker");
 	res_push_fun(warp_new, warp_property, "warp");
 }
diff --git a/src/walker.c b/src/walker.c
new file mode 100644
index 0000000..9a74816
--- /dev/null
+++ b/src/walker.c
@@ -0,0 +1,329 @@
+#include "main.h"
+#include "entity.h"
+#include "loader.h"
+#include "input.h"
+#include "tilemap.h"
+#include <stdbool.h>
+
+#define SIZE 4
+#define ACCELERATION 2
+#define FRICTION 3
+#define MAX_SPEED 16
+#define GRAVITY 2
+#define JUMP 40
+
+enum {
+	WALKER_NONE,
+	WALKER_IDLE,
+	WALKER_PATROL,
+	WALKER_ALERT,
+	WALKER_ATTACK,
+};
+
+enum {
+	WALKER_A_IDLE,
+	WALKER_A_IDLE2,
+	WALKER_A_WALK,
+	WALKER_A_WALK2,
+	WALKER_A_WALK3,
+	WALKER_A_WALK4,
+	WALKER_A_JUMP,
+	WALKER_A_FALL,
+	WALKER_A_FALL2,
+};
+
+struct anim walker_anims[] = {
+	{WALKER_A_IDLE2, {0, 0, 16, 16}, 300},
+	{WALKER_A_IDLE, {0, 32, 16, 16}, 2},
+	{WALKER_A_WALK2, {0, 0, 16, 16}, 6},
+	{WALKER_A_WALK3, {16, 0, 16, 16}, 6},
+	{WALKER_A_WALK4, {32, 0, 16, 16}, 6},
+	{WALKER_A_WALK, {48, 0, 16, 16}, 6},
+	{WALKER_A_JUMP, {16, 0, 16, 16}, 300},
+	{WALKER_A_FALL2, {32, 0, 16, 16}, 15},
+	{WALKER_A_FALL2, {48, 0, 16, 16}, 15},
+};
+
+static int bullet_update(struct projectile *self) {
+	self->x += self->velocity.x;
+	if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x), from_fixed(self->y)))) {
+		self->velocity.x = -self->velocity.x;
+		self->x += self->velocity.x;
+	}
+		
+	self->y += self->velocity.y;
+	if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x), from_fixed(self->y)))) {
+		self->velocity.y = -self->velocity.y;
+		self->y += self->velocity.y;
+	}
+
+	self->hp--;
+	int x = from_fixed(self->x);
+	int y = from_fixed(self->y);
+	self->hitbox = (struct hitbox) {.left = x, .right = x, .top = y, .bottom = y};
+	#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 bullet_draw(struct projectile *self, int camX, int camY) {
+	SDL_Rect rect = {4, 0, 4, 4};
+	SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 1, from_fixed(self->y) - camY - 1, 4, 4});
+	SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x - self->velocity.x) - camX - 1, from_fixed(self->y - self->velocity.y) - camY - 1, 4, 4});
+	//SDL_RenderFillRect(renderer, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+	return 0;
+}
+
+static void bullet_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, signed direction) {
+	int on_ground = false;
+	int const dx = direction * ACCELERATION;
+	self->velocity.x += dx;
+	// deaccel
+	if (dx == 0) {
+		if (self->velocity.x < -FRICTION) {
+			self->velocity.x += FRICTION;
+		} else if (self->velocity.x > FRICTION) {
+			self->velocity.x -= FRICTION;
+		} else {
+			self->velocity.x = 0;
+		}
+	}
+	// speed cap
+	if (self->velocity.x > MAX_SPEED) {
+		self->velocity.x = MAX_SPEED;
+	} else if (self->velocity.x < -MAX_SPEED) {
+		self->velocity.x = -MAX_SPEED;
+	}
+	// x collision
+	self->x += self->velocity.x;
+	collision_T const cx = collide(self);
+	if (collision_solid(cx)) {
+		if (self->velocity.x < 0) {
+			self->x += to_fixed(8) - ((self->x - to_fixed(SIZE / 2)) % to_fixed(8)); // left
+		} else if (self->velocity.x == 0) {
+			//fputs("what?\n", stderr);
+		} else {
+			self->x -= ((self->x + to_fixed(SIZE / 2)) % to_fixed(8)); // right
+		}
+		self->velocity.x = 0;
+	}
+	if (self->velocity.x < 0) {
+		self->facing = -1;
+	} else if (self->velocity.x > 0) {
+		self->facing = +1;
+	}
+	self->velocity.y += GRAVITY;
+	// y collision
+	self->y += self->velocity.y;
+	collision_T const cy = collide(self);
+	if (collision_solid(cy)) {
+		if (self->velocity.y < 0) {
+			self->y += to_fixed(8) - ((self->y - to_fixed(SIZE)) % to_fixed(8)); // up
+			self->velocity.y = 0;
+		} else if (self->velocity.y == 0) {
+			//fputs("what?\n", stderr);
+		} else {
+			self->y -= ((self->y) % to_fixed(8)); // down
+			self->velocity.y = to_fixed(1); // crazy but it works
+			on_ground = true;
+		}
+	}
+	
+	if (collision_hazard(cx | cy)) {
+		self->hurt(self, 1);
+	}
+	
+	self->hitbox.left = from_fixed(self->x) - SIZE / 2;
+	self->hitbox.right = from_fixed(self->x) + SIZE / 2;
+	self->hitbox.top = from_fixed(self->y) - SIZE;
+	self->hitbox.bottom = from_fixed(self->y);
+	return on_ground;
+}
+
+static void anim(struct entity *self, unsigned anim) {
+	self->anim = walker_anims[anim];
+}
+
+static void attack(struct entity *self) {
+	entities.projectile[entities.projectiles] = (struct projectile) {
+		.update = bullet_update,
+		.draw = bullet_draw,
+		.free = bullet_free,
+		.x = self->x, .y = self->y - to_fixed(3),
+		.velocity = (struct vec2) {self->velocity.x + to_fixed(self->facing), 0},
+		.hitbox = {
+			0, 0, 0, 0,
+		},
+		.state = WALKER_IDLE,
+		.hp = 300,
+		.timer = 0,
+		.facing = self->facing,
+		.faction = FACTION_ENEMY,
+		.iframes = 0,
+		.texture = NULL,
+		.ext = NULL,
+	};
+	//anim(entities->projectile + entities->projectiles, WALKER_A_IDLE);
+	entities.projectile[entities.projectiles].texture = res_get_texture("particles").data;
+	entities.projectiles++;
+}
+
+static int walker_update(struct entity *self) {
+	if (self->hp <= 0) {
+		self->state = 0;
+		entities.enemies--;
+		return 1;
+	}
+	switch (self->state) {
+		case WALKER_IDLE:
+			if (move(self, 0) == false) {
+				abort();
+				self->velocity.y = 0;
+				anim(self, WALKER_A_FALL);
+				//self->state = WALKER_FALL;
+			}
+			self->timer--;
+			if (self->timer == 0) {
+				self->facing = -self->facing;
+				anim(self, WALKER_A_WALK);
+				self->state = WALKER_PATROL;
+			}
+			break;
+
+		case WALKER_PATROL:
+			if (move(self, self->facing) == false) {
+				abort();
+				self->velocity.y = 0;
+				anim(self, WALKER_A_FALL);
+				//self->state = WALKER_FALL;
+			}
+			if (collision_solid(tilemap_tile(tilemap, from_fixed(self->x) + self->facing * 8, from_fixed(self->y) - 4)) ||
+			!collision_solid(tilemap_tile(tilemap, from_fixed(self->x) + self->facing * 8, from_fixed(self->y) + 4))) {
+				anim(self, WALKER_A_IDLE);
+				self->state = WALKER_IDLE;
+				self->timer = 30;
+			}
+			break;
+		
+		case WALKER_ALERT:
+			attack(self);
+			if (!input_a(input_held)) {
+				self->velocity.y /= 2;
+				anim(self, WALKER_A_FALL);
+				//self->state = WALKER_FALL;
+			}
+			if (self->velocity.y > 0) {
+				anim(self, WALKER_A_FALL);
+				//self->state = WALKER_FALL;
+			}
+			if (move(self, 0) == true) {
+				anim(self, WALKER_A_IDLE);
+				self->state = WALKER_IDLE;
+			}
+			break;
+		
+		case WALKER_ATTACK:
+			if (move(self, 0) == true) {
+				anim(self, WALKER_A_IDLE);
+				self->state = WALKER_IDLE;
+			}
+			break;
+	}
+	if (self->iframes > 0) {
+		self->iframes--;
+	}
+	self->anim.length--;
+	if (self->anim.length == 0) {
+		anim(self, self->anim.frame);
+	}
+	return 0;
+}
+
+static int walker_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) {4, 0, 4, 4};
+				part->acceleration = (struct vec2) {0, 1};
+				part->hp = 30;
+				entities.particles++;
+			}
+		}
+	}
+	return 0;
+}
+
+static int walker_draw(struct entity *self, int camX, int camY) {
+	if (!(self->iframes & 0x4)) {
+		SDL_Rect rect = self->anim.rect;
+		if (self->facing == -1) {
+			rect.y += 16;
+		}
+		SDL_RenderCopy(renderer, self->texture, &rect, &(SDL_Rect) {from_fixed(self->x) - camX - 8, from_fixed(self->y) - camY - 12, 16, 16});
+	}
+	return 0;
+}
+
+static void walker_free(struct entity *self) {
+	self->state = 0;
+}
+
+struct entity *walker_new(struct entities *entities) {
+	entities->enemy[entities->enemies] = (struct entity) {
+		.update = walker_update,
+		.hurt = walker_hurt,
+		.draw = walker_draw,
+		.free = walker_free,
+		.x = 0, .y = 0,
+		.velocity = {.x = 0, .y = to_fixed(1)},
+		.hitbox = {
+			0, 0, 0, 0,
+		},
+		.state = WALKER_PATROL,
+		.hp = 3,
+		.timer = 0,
+		.facing = 1,
+		.faction = FACTION_ENEMY,
+		.iframes = 0,
+		.texture = NULL,
+		.ext = NULL,
+	};
+	anim(entities->enemy + entities->enemies, WALKER_A_IDLE);
+	entities->enemy[entities->enemies].texture = res_get_texture("fywi").data;
+	return entities->enemy + entities->enemies++;
+}
+
+int walker_property(struct entity *const restrict self, char const *const restrict property, char const *const restrict value) {
+	if (strcmp(property, "x") == 0) {
+		self->x = to_fixed(atoi(value));
+	} else if (strcmp(property, "y") == 0) {
+		self->y = to_fixed(atoi(value));
+	} else {
+		return 1;
+	}
+	return 0;
+}