enemy.c (7544B)
1 #include <stdlib.h> 2 #include <math.h> 3 4 #include "../include/enemy.h" 5 #include "../include/const.h" 6 #include "../include/entity.h" 7 #include "../include/effect.h" 8 9 enemy_t *enemy_create(pos_t pos, enemy_e type) { 10 enemy_t *enemy = malloc(sizeof(enemy_t)); 11 *enemy = (enemy_t) { 12 .pos = pos, 13 .type = type, 14 .on_ground = false, 15 .velocity = 0.0, 16 .gravity = 0.0, 17 .dir = 1, 18 .stunned = false, 19 .frozen = false, 20 .frozen_timer = 0, 21 .fall_height = 0.0, 22 .timer_walking = fz_timer_create(9, 8), 23 .timer_sneaking = fz_timer_create(9, 16), 24 }; 25 return enemy; 26 } 27 28 void enemy_update(enemy_t *enemy, game_t *game) { 29 enemy->stunned = false; 30 bool on_ground = false; 31 // not beeing held 32 if (game->player->held_enemy != enemy) { 33 // detect on ground 34 if (!(enemy->velocity > 0.0)) { 35 for (int i = 0; i < game->tiles_len; i++) { 36 tile_t *tile = game->tiles[i]; 37 if (tile_ground(tile)) { 38 if ( 39 enemy->pos.x + PLAYER_WIDTH > tile->pos.x && 40 enemy->pos.x < tile->pos.x + TILE_WIDTH 41 ) { 42 float tolerance = 4.0; 43 if (enemy->gravity > tolerance) { 44 tolerance = enemy->gravity; 45 } 46 if (fabs(enemy->pos.y + PLAYER_HEIGHT - tile->pos.y) < tolerance) { 47 enemy->pos.y = tile->pos.y - PLAYER_HEIGHT; 48 on_ground = true; 49 if (enemy->fall_height >= 2 * TILE_HEIGHT) { 50 effect_play(enemy->pos, EFFECT_BREAK, game); 51 effect_play(enemy->pos, EFFECT_PARTICLE, game); 52 enemy_kill(enemy, game); 53 } 54 } 55 } 56 } 57 } 58 } 59 enemy->on_ground = on_ground; 60 if (enemy->on_ground) { 61 enemy->gravity = 0.0; 62 enemy->fall_height = 0.0; 63 } 64 else { 65 enemy->pos.y += enemy->gravity; 66 enemy->fall_height += enemy->gravity; 67 if (enemy->gravity < PLAYER_GRAVITY) { 68 enemy->gravity += 0.2; 69 } 70 else { 71 enemy->gravity = PLAYER_GRAVITY; 72 } 73 } 74 // handle shooting 75 if ( 76 game->player->shooting && 77 game->player->target_entity != NULL && 78 game->player->target_entity->type == ENTITY_ENEMY && 79 game->player->target_entity->enemy == enemy 80 ) { 81 if (enemy->frozen) { 82 bool is_colliding = false; 83 rect_t enemy_rect = { enemy->pos.x, enemy->pos.y, ENEMY_WIDTH, ENEMY_HEIGHT }; 84 for (int i = 0; i < game->tiles_len; i++) { 85 tile_t *tile = game->tiles[i]; 86 if (tile_wall(tile)) { 87 rect_t tile_rect = { tile->pos.x, tile->pos.y, TILE_WIDTH, TILE_HEIGHT }; 88 if (rect_collide(enemy_rect, tile_rect)) { 89 is_colliding = true; 90 break; 91 } 92 } 93 } 94 if (!is_colliding) { 95 if (game->player->dir > 0) { 96 enemy->pos.x += 2.0; 97 } 98 else { 99 enemy->pos.x -= 2.0; 100 } 101 } 102 } 103 else { 104 enemy->stunned = true; 105 } 106 } 107 } 108 // handle freezing 109 if (!enemy->frozen) { 110 if (enemy->stunned) { 111 if (enemy->frozen_timer >= 100) { 112 enemy->frozen = true; 113 enemy->frozen_timer = 0; 114 } 115 enemy->frozen_timer++; 116 } 117 else if (enemy->frozen_timer > 0) { 118 enemy->frozen_timer--; 119 } 120 } 121 else { 122 if (enemy->frozen_timer >= 1500) { 123 enemy->frozen = false; 124 enemy->frozen_timer = 0; 125 if (game->player->held_enemy == enemy) { 126 game->player->held_enemy = NULL; 127 } 128 } 129 enemy->frozen_timer++; 130 } 131 // handle movement 132 tile_t *next_ground_tile = tile_get(game, enemy->pos.x + ENEMY_WIDTH / 2.0 + enemy->dir * ENEMY_WIDTH / 6.0, enemy->pos.y + ENEMY_HEIGHT + 1); 133 if (!enemy->frozen) { 134 if (enemy->on_ground && (next_ground_tile == NULL || next_ground_tile->type == TILE_AIR)) { 135 enemy->dir = -enemy->dir; 136 } 137 if (enemy->stunned) { 138 enemy->pos.x += enemy->dir * 0.1; 139 } 140 else { 141 enemy->pos.x += enemy->dir * 0.5; 142 } 143 } 144 // detect wall and direction change 145 if (!enemy->frozen) { 146 for (int i = 0; i < game->tiles_len; i++) { 147 tile_t *tile = game->tiles[i]; 148 if (tile_wall(tile)) { 149 if ( 150 enemy->pos.y + ENEMY_HEIGHT > tile->pos.y && 151 enemy->pos.y < tile->pos.y + TILE_HEIGHT 152 ) { 153 float tolerance = 4.0; 154 if (enemy->dir > 0) { 155 if (fabs((enemy->pos.x + ENEMY_WIDTH - 0.4 * TILE_WIDTH) - tile->pos.x) < tolerance) { 156 enemy->dir = -enemy->dir; 157 } 158 } 159 else { 160 if (fabs((enemy->pos.x + 0.4 * TILE_WIDTH) - (tile->pos.x + TILE_WIDTH)) < tolerance) { 161 enemy->dir = -enemy->dir; 162 } 163 } 164 } 165 } 166 } 167 } 168 // fall out of map 169 if (enemy->pos.y > TILE_HEIGHT * game->level->height) { 170 pos_t pos = { enemy->pos.x, enemy->pos.y - ENEMY_HEIGHT + ENEMY_HEIGHT / 3.0 }; 171 effect_play(pos, EFFECT_PARTICLE, game); 172 enemy_kill(enemy, game); 173 } 174 // update timer 175 if (enemy->on_ground && !enemy->frozen) { 176 fz_timer_update(enemy->timer_walking); 177 fz_timer_update(enemy->timer_sneaking); 178 } 179 else { 180 fz_timer_reset(enemy->timer_walking); 181 fz_timer_reset(enemy->timer_sneaking); 182 } 183 } 184 185 void enemy_draw(enemy_t *enemy, game_t *game) { 186 pos_t pos = pos_snap(enemy->pos); 187 int frame_walking = fz_timer_get(enemy->timer_walking); 188 int frame_sneaking = fz_timer_get(enemy->timer_sneaking); 189 if (enemy->dir > 0) { 190 DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 10, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 191 } 192 else { 193 DrawTextureRec(game->assets.entities, texture_rect(enemy->stunned ? frame_sneaking : frame_walking, 11, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 194 } 195 if (enemy->frozen) { 196 if (enemy->frozen_timer <= 1200) { 197 DrawTextureRec(game->assets.entities, texture_rect(3, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 198 } 199 else if (enemy->frozen_timer <= 1350) { 200 DrawTextureRec(game->assets.entities, texture_rect(4, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 201 } 202 else if (enemy->frozen_timer <= 1450) { 203 DrawTextureRec(game->assets.entities, texture_rect(5, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 204 } 205 else { 206 DrawTextureRec(game->assets.entities, texture_rect(6, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 207 } 208 } 209 else if (enemy->stunned) { 210 if (enemy->frozen_timer <= 33) { 211 DrawTextureRec(game->assets.entities, texture_rect(0, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 212 } 213 else if (enemy->frozen_timer <= 66) { 214 DrawTextureRec(game->assets.entities, texture_rect(1, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 215 } 216 else { 217 DrawTextureRec(game->assets.entities, texture_rect(2, 2, PLAYER_WIDTH, PLAYER_HEIGHT), pos, WHITE); 218 } 219 } 220 } 221 222 void enemy_kill(enemy_t *enemy, game_t *game) { 223 for (int i = 0; i < game->entities_len; i++) { 224 if (game->entities[i].type == ENTITY_ENEMY && game->entities[i].enemy == enemy) { 225 if (i + 1 < game->entities_len) { 226 for (int j = i; j < game->entities_len - 1; j++) { 227 game->entities[j] = game->entities[j + 1]; 228 } 229 } 230 game->entities_len--; 231 game->entities = realloc(game->entities, sizeof(entity_t) * game->entities_len); 232 game->xp += 10; 233 break; 234 } 235 } 236 } 237 238 void enemy_free(enemy_t *enemy) { 239 fz_timer_free(enemy->timer_walking); 240 fz_timer_free(enemy->timer_sneaking); 241 free(enemy); 242 }