#include "main.h" #include "entity.h" #include "loader.h" #include "input.h" #include "tilemap.h" #include #include #define SIZE 4 #define ACCELERATION 1 #define FRICTION 2 #define MAX_SPEED 12 #define GRAVITY 1 #define JUMP 30 #define SLASH_REACH_X 8 #define SLASH_REACH_Y 6 enum { PLAYER_NONE, PLAYER_IDLE, PLAYER_ATTACK1, PLAYER_ATTACK2, PLAYER_ATTACK3, PLAYER_WALK, PLAYER_JUMP, PLAYER_FALL, }; enum { PLAYER_A_IDLE, PLAYER_A_IDLE2, PLAYER_A_WALK, PLAYER_A_WALK2, PLAYER_A_WALK3, PLAYER_A_WALK4, PLAYER_A_JUMP, PLAYER_A_FALL, PLAYER_A_FALL2, }; struct anim player_anims[] = { {PLAYER_A_IDLE2, {0, 0, 16, 16}, 300}, {PLAYER_A_IDLE, {0, 32, 16, 16}, 2}, {PLAYER_A_WALK2, {0, 0, 16, 16}, 6}, {PLAYER_A_WALK3, {16, 0, 16, 16}, 6}, {PLAYER_A_WALK4, {32, 0, 16, 16}, 6}, {PLAYER_A_WALK, {48, 0, 16, 16}, 6}, {PLAYER_A_JUMP, {16, 0, 16, 16}, 300}, {PLAYER_A_FALL2, {32, 0, 16, 16}, 15}, {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; if (self->hp >= 0) { self->hp--; } else { self->hp++; } int x = from_fixed(self->x) + self->facing * sin(self->hp / 2) * SLASH_REACH_X; int y = from_fixed(self->y) - cos(self->hp / 2) * SLASH_REACH_Y; int xx = from_fixed(self->x) + self->facing * sin(self->hp / 2 + 1) * SLASH_REACH_X; int yy = from_fixed(self->y) - cos(self->hp / 2 + 1) * SLASH_REACH_Y; self->hitbox = (struct hitbox) {.left = x - 2, .right = x + 2, .top = y - 2, .bottom = y + 2}; for (int i = 0, e = entities.enemies; i < 64 && e; i++) { if (entities.enemy[i].state) { e--; } else { continue; } if (entities.enemy[i].faction == self->faction) { continue; } if (hitbox_overlap(self->hitbox, entities.enemy[i].hitbox)) { entities.enemy[i].hurt(entities.enemy + i, 1); } } struct particle *part = entities.particle + entities.particles; part->x = to_fixed(x - 1); part->y = to_fixed(y - 1); part->velocity = (struct vec2) {self->velocity.x + x - xx, self->velocity.y + y - yy}; part->rect = (SDL_Rect) {8, 0, 4, 4}; part->acceleration = (struct vec2) {0, 0}; part->hp = 10 - (self->hp >= 0? self->hp: -self->hp - 8); entities.particles++; if (self->hp == 0 || self->hp == -8) { 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; if (self->hp >= 0) { SDL_Vertex vertices[4] = { {.position = {x + from_fixed(self->velocity.x) + self->facing * sin(self->hp / 2 - 1) * SLASH_REACH_X, y - cos(self->hp / 2 - 1) * SLASH_REACH_Y}, .color = {255, 191, 63, 255}}, {.position = {x + self->facing * sin(self->hp / 2 + 0) * SLASH_REACH_X, y - cos(self->hp / 2 + 0) * SLASH_REACH_Y}, .color = {255, 127, 0, 255}}, {.position = {x - from_fixed(self->velocity.x) + self->facing * sin(self->hp / 2 + 1) * SLASH_REACH_X, y - cos(self->hp / 2 + 1) * SLASH_REACH_Y}, .color = {255, 127, 0, 255}}, {.position = {x - from_fixed(self->velocity.x * 2) + self->facing * sin(self->hp / 2 + 2) * SLASH_REACH_X, y - cos(self->hp / 2 + 2) * SLASH_REACH_Y}, .color = {255, 127, 0, 0}}, }; SDL_RenderGeometry(renderer, NULL, vertices, 4, (int []) {0, 1, 2, 0, 2, 3}, 6); } else { SDL_Vertex vertices[4] = { {.position = {x - from_fixed(self->velocity.x) + self->facing * sin(self->hp / 2 + 1) * SLASH_REACH_X, y - cos(self->hp / 2 + 1) * SLASH_REACH_Y}, .color = {255, 191, 63, 255}}, {.position = {x + + self->facing * sin(self->hp / 2 + 0) * SLASH_REACH_X, y - cos(self->hp / 2 + 0) * SLASH_REACH_Y}, .color = {255, 127, 0, 255}}, {.position = {x + from_fixed(self->velocity.x) + self->facing * sin(self->hp / 2 - 1) * SLASH_REACH_X, y - cos(self->hp / 2 - 1) * SLASH_REACH_Y}, .color = {255, 127, 0, 255}}, {.position = {x + from_fixed(self->velocity.x * 2) + self->facing * sin(self->hp / 2 - 2) * SLASH_REACH_X, y - cos(self->hp / 2 - 2) * SLASH_REACH_Y}, .color = {255, 127, 0, 0}}, }; SDL_RenderGeometry(renderer, NULL, vertices, 4, (int []) {0, 1, 2, 0, 2, 3}, 6); } 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_held) - input_left(input_held)) * 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 attack(struct entity *self, int a) { 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 = a? 8: -16, .timer = 0, .facing = self->facing, .faction = FACTION_PLAYER, .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]; } static int player_update(struct entity *self) { if (self->hp <= 0) { self->state = 0; return 1; } switch (self->state) { case PLAYER_IDLE: if (move(self) == false) { self->velocity.y = 0; anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (input_right(input_held) - input_left(input_held)) { anim(self, PLAYER_A_WALK); self->state = PLAYER_WALK; } if (input_a(input_held)) { self->velocity.y = -JUMP; anim(self, PLAYER_A_JUMP); self->state = PLAYER_JUMP; struct particle *part = entities.particle + entities.particles; part->x = self->x - to_fixed(-3) - to_fixed(1); part->y = self->y - 2; part->velocity = (struct vec2) {12, -8}; part->rect = (SDL_Rect) {0, 0, 4, 4}; part->acceleration = (struct vec2) {0, 1}; part->hp = 5; entities.particles++; part = entities.particle + entities.particles; part->x = self->x - to_fixed(3) - to_fixed(1); part->y = self->y - 2; part->velocity = (struct vec2) {-12, -8}; part->rect = (SDL_Rect) {0, 0, 4, 4}; part->acceleration = (struct vec2) {0, 1}; part->hp = 5; entities.particles++; } attack(self, 1); if (input_s(input_pressed)) { self->state = PLAYER_ATTACK1; self->timer = 30; } break; case PLAYER_ATTACK1: if (move(self) == false) { self->velocity.y = 0; anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (input_right(input_held) - input_left(input_held)) { anim(self, PLAYER_A_WALK); self->state = PLAYER_WALK; } if (input_a(input_held)) { self->velocity.y = -JUMP; anim(self, PLAYER_A_JUMP); self->state = PLAYER_JUMP; } attack(self, 0); if (input_s(input_pressed)) { self->state = PLAYER_ATTACK2; self->timer = 30; } if (self->timer-- == 0) { self->state = PLAYER_IDLE; } break; case PLAYER_ATTACK2: if (move(self) == false) { self->velocity.y = 0; anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (input_right(input_held) - input_left(input_held)) { anim(self, PLAYER_A_WALK); self->state = PLAYER_WALK; } if (input_a(input_held)) { self->velocity.y = -JUMP; anim(self, PLAYER_A_JUMP); self->state = PLAYER_JUMP; } attack(self, 1); if (input_s(input_pressed)) { self->state = PLAYER_ATTACK3; self->timer = 60; } if (self->timer-- == 0) { self->state = PLAYER_IDLE; } break; case PLAYER_ATTACK3: if (move(self) == false) { self->velocity.y = 0; anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (input_right(input_held) - input_left(input_held)) { anim(self, PLAYER_A_WALK); self->state = PLAYER_WALK; } if (input_a(input_held)) { self->velocity.y = -JUMP; anim(self, PLAYER_A_JUMP); self->state = PLAYER_JUMP; } if (self->timer-- == 0) { self->state = PLAYER_IDLE; } break; 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_held) - input_left(input_held))) { anim(self, PLAYER_A_IDLE); self->state = PLAYER_IDLE; } if (input_a(input_held)) { self->velocity.y = -JUMP; anim(self, PLAYER_A_JUMP); self->state = PLAYER_JUMP; } attack(self, 1); break; case PLAYER_JUMP: if (!input_a(input_held)) { self->velocity.y /= 2; anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (self->velocity.y > 0) { anim(self, PLAYER_A_FALL); self->state = PLAYER_FALL; } if (move(self) == true) { anim(self, PLAYER_A_IDLE); self->state = PLAYER_IDLE; } break; 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; } if (self->iframes > 0) { self->iframes--; } self->anim.length--; if (self->anim.length == 0) { anim(self, self->anim.frame); } return 0; } 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) {4, 0, 4, 4}; part->acceleration = (struct vec2) {0, 1}; part->hp = 30; entities.particles++; } } } return 0; } static int player_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; } struct entity *player_new(struct entities *entities) { entities->player[0] = (struct entity) { .update = player_update, .hurt = player_hurt, .draw = player_draw, .x = 0, .y = 0, .velocity = {.x = 0, .y = 0}, .hitbox = { 0, 0, 0, 0, }, .state = PLAYER_IDLE, .hp = 3, .timer = 0, .facing = 1, .faction = FACTION_PLAYER, .iframes = 0, .texture = NULL, .ext = NULL, }; anim(entities->player, PLAYER_A_IDLE); entities->player[0].texture = res_get_texture("fywi").data; return entities->player + 0; } int player_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; }