QUOTE: Love yourself first, then others.

enemy.c - freezo - A retro platform game

freezo

A retro platform game
git clone git@soophie.de:/srv/git/freezo
log | files | refs | readme

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 }