so://phie

freezo

A retro platform game
git clone git://soophie.de/freezo

blob: d4b9d4e4e550cdd07f569e8d40fa6002678c4d7f (7544 bytes)[raw]

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}