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