A retro platform game
git clone git://soophie.de/freezo
blob: d4b9d4e4e550cdd07f569e8d40fa6002678c4d7f (7544 bytes)[raw]
1
#include <stdlib.h>2
#include <math.h>4
#include "../include/enemy.h"5
#include "../include/const.h"6
#include "../include/entity.h"7
#include "../include/effect.h"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
}28
void enemy_update(enemy_t *enemy, game_t *game) {29
enemy->stunned = false;30
bool on_ground = false;31
// not beeing held32
if (game->player->held_enemy != enemy) {33
// detect on ground34
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_WIDTH41
) {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 shooting75
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 == enemy80
) {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 freezing109
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 movement132
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 change145
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_HEIGHT152
) {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 map169
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 timer175
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
}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
}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
}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
}