QUOTE: Love yourself first, then others.

freezo

A retro platform game

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
      9enemy_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
     28void 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
    185void 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
    222void 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
    238void enemy_free(enemy_t *enemy) {
    239  fz_timer_free(enemy->timer_walking);
    240  fz_timer_free(enemy->timer_sneaking);
    241  free(enemy);
    242}