-
Notifications
You must be signed in to change notification settings - Fork 0
/
so_long.h
487 lines (416 loc) · 17.9 KB
/
so_long.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/* ************************************************************************** */
/* */
/* :::::::: */
/* so_long.h :+: :+: */
/* +:+ */
/* By: cschuijt <[email protected]> +#+ */
/* +#+ */
/* Created: 2022/11/11 14:32:03 by cschuijt #+# #+# */
/* Updated: 2022/11/11 14:32:03 by cschuijt ######## odam.nl */
/* */
/* ************************************************************************** */
#ifndef SO_LONG_H
# define SO_LONG_H
// -- INCLUDES --
# include "libft/libft.h"
# include <stddef.h>
# include <stdint.h>
# include <MLX42/MLX42.h>
// -- DEFINES --
// The minimum width of the window in map tiles, to ensure the GUI can be
// properly drawn.
# define MIN_MAP_W 12
// Amount of pixels that the map rendering needs to be offset by to make room
// for the GUI above.
# define GUI_OFFSET 128
// Amount of seconds that should be between animation frames for background
// sprites (lava/candles)
# define BG_ANIMATION_INTERVAL 0.09
// Amount of seconds that should be between frames for idle animation of
// characters (player and patrols)
# define IDLE_ANIMATION_INTERVAL 0.12
// Amount of seconds that should be between frames of movement for
// the player and patrols
# define MOVE_ANIMATION_INTERVAL 0.045
// Sprite height for projecting onto other images
# define SPRITE_H 32
// Sprite width for projecting onto other images
# define SPRITE_W 32
// RGBA color to render text in
# define TEXT_COLOR 0x000000FF
// Font dimensions in the spritesheet and pixel buffers
# define FONT_SPRITE_DIMS 32
// Font width for projecting letters subsequently onto other images
# define FONT_W 11
// -- ENUMS --
typedef enum e_render_layers {
layer_bg,
layer_bg_sprites,
layer_shadows,
layer_collectibles,
layer_indicators,
layer_patrols,
layer_player,
layer_pillars,
layer_gui_moves,
layer_gui_cols,
layer_endscreen
} t_render_layers;
typedef enum e_direction {
dir_up,
dir_right,
dir_down,
dir_left
} t_direction;
typedef enum e_game_state {
state_playing,
state_loss_animation,
state_game_over,
state_victory
} t_game_state;
// -- STRUCTS --
// @brief One sprite, instantiated from a larger spritesheet.
//
// Sprites are a singly linked list of all background tiles loaded into
// an MLX image. By using the list, sprites that are needed more than once
// are only turned into an image once, and just reinstantiated after that.
// Setting a number of animation frames will tell the game to loop through
// a number of consecutive sprites on a clock, keeping the same image but
// repeatedly changing its pixel buffer.
//
// @param spritesheet The array of pixel buffers this sprite originated from.
// @param index The index in spritesheet at which this sprite is located.
// @param image The MLX image at which this sprite is instantiated.
// @param next The next sprite, or NULL if this is the end of the list.
// @param animation_frames The amount of consecutive sprites that form an
// animation loop.
typedef struct s_sprite {
uint8_t **spritesheet;
size_t index;
mlx_image_t *image;
int animation_frames;
struct s_sprite *next;
} t_sprite;
// @brief A floor tile spanning one or more spaces on the map.
//
// Floor tiles are a circular linked list, allowing the sprite setter to loop
// through them as much as needed to fill in all open floor spaces. The pattern
// in a floor tile is an unsigned char array of six characters, describing the
// following spaces in clockwise order:
//
// 0 1
// 4 3 2
//
// Each character's numeric value tells the game which sprite to fill in at
// that location, using position 0 as the reference point. If a character is
// set to byte value zero, that tile is not considered for fitting the tile,
// and will not be overridden when deciding to place it.
typedef struct s_floortile {
char *pattern;
struct s_floortile *next;
} t_floortile;
// @brief A list of the collectibles on the map.
//
// Collectibles are a singly linked list describing each collectible on the map,
// including whether it's been picked up or not and which instance ID is
// responsible for rendering this particular collectible. By iterating over this
// list, the game can determine how many collectibles have been picked up and
// whether to allow the player to finish the game.
//
// @param pos The location on the map where this collectible is at.
// @param instance The instance ID with which this collectible is rendered.
// @param picked_up 0 if not picked up, 1 if picked up.
typedef struct s_collectible {
size_t pos;
size_t instance;
uint8_t picked_up;
struct s_collectible *next;
} t_collectible;
// @brief A struct representing all variables to do with the player entity.
//
// @param image The MLX image with which the player is rendered.
// @param pos The position of the player on the map.
// @param moves_taken Amount of moves taken by the player.
// @param move_direction A number from e_direction to indicate which way the
// player is moving.
// @param facing_offset The amount by which the sprite index needs to change
// based on which way the player is facing right now. 4 for left, 0 for right.
typedef struct s_player {
mlx_image_t *image;
size_t pos;
size_t moves_taken;
size_t move_direction;
size_t facing_offset;
} t_player;
// @brief Struct for a single enemy patrol.
//
// @param image The MLX image with which this patrol is rendered.
// @param pos The position of this patrol on the map.
// @param move_direction A number from e_direction to indicate the direction
// this patrol is currently moving in.
// @param facing_offset The amount of sprites to offset rendering by,
// should be 0 or 4.
// @param next The next patrol in the list, or NULL if last patrol.
typedef struct s_patrol {
mlx_image_t *image;
size_t pos;
size_t move_direction;
size_t facing_offset;
size_t indicator_instance;
struct s_patrol *next;
} t_patrol;
// @brief Struct for all game data, from the map to sprites to MLX.
//
// @param mlx The MLX instance this map is being rendered in.
// @param map_name Name of the map file loaded into the game.
// @param content String containing the map as it is in the file,
// stripped of newlines.
// @param sprite_categories String containing letters indicating which kind of
// sprites need to be used for each space on the map:
// W = wall, L = lava,
// N = front-facing wall, F = floor,
// P = pillar, E = exit
// @param render_terrain Unsigned char array of sprite indices for the
// background of each space on the map.
// sprite_categories indicates which spritesheet
// the index refers to.
// @param render_shadows Unsigned char array of sprite indices for the
// shadows on each space of the map.
// @param background MLX image for the background layer of the game,
// which should be filled with a single color. Also
// contains the parts of the GUI which do not need to
// update as the game runs.
// @param gui_moves MLX image for the move count in the GUI.
// @param gui_collectibles MLX image for the currently picked up collectible
// count in the GUI.
// @param height Total height of the map, in spaces.
// @param width Total width of the map, in spaces.
// @param size Total size of the map, in spaces.
// @param player Struct containing all player entity information.
// @param movement_clock Clock that counts up for each animation frame in a
// player move, tells those functions which frame to
// display next.
// @param lock_input When not 0, tells the game to ignore inputs because
// an animation is playing.
// @param col_total Total amount of collectibles on the map.
// @param col_grabbed Amount of collectibles grabbed by the player.
// @param collectibles Linked list of collectibles with their location and
// render instance.
// @param bg_sprites Spritesheet containing the background sprites,
// floors, walls, etc.
// @param lava_sprites Spritesheet containing the lava streams.
// @param shadow_sprites Spritesheet containing the shadow sprites.
// @param player_sprites Spritesheet containing all animation frames for the
// player character.
// @param patrol_sprites Spritesheet containing all animation frames for the
// enemies.
// @param gui_bg_sprites Spritesheet containing the background tiles for
// the GUI.
// @param gui_charset Spritesheet containing the letters to draw onto
// the GUI.
// @param sprites Linked list of instantiated background sprites to
// avoid creating more MLX images than required.
typedef struct s_map {
mlx_t *mlx;
char *map_name;
char *content;
char *sprite_categories;
char *render_terrain;
char *render_shadows;
mlx_image_t *background;
size_t height;
size_t width;
size_t size;
t_player *player;
t_patrol *patrols;
int movement_clock;
int lock_input;
int game_state;
size_t col_total;
char *col_total_str;
size_t col_grabbed;
t_collectible *collectibles;
mlx_image_t *move_counter;
mlx_image_t *col_counter;
uint8_t **bg_sprites;
uint8_t **lava_sprites;
uint8_t **shadow_sprites;
uint8_t **player_sprites;
uint8_t **patrol_sprites;
uint8_t **gui_bg_sprites;
uint8_t **gui_end_sprites;
uint8_t **gui_charset;
t_sprite *sprites;
} t_map;
// -- MAP INITIALIZATION --
t_map *initialize_map(char *path);
char *read_map_from_file(int fd);
void initialize_map_player(t_map *map, size_t player_pos);
void fill_in_map_name(t_map *map, char *path);
void fit_map_array_to_window(char ***map_array);
void add_top_row(char ***map_array);
void set_additional_map_variables(t_map *map, size_t player_pos);
// -- SPRITESHEETS --
uint8_t **read_spritesheet(char *path, size_t dim, size_t w, size_t h);
uint8_t *crop_buffer(uint8_t *texture, size_t i, size_t dim, size_t w);
void load_spritesheets(t_map *map);
void sprite_buffer_to_image(uint8_t *buffer, mlx_image_t *image, \
size_t x, size_t y);
// -- TEXT RENDERING --
void string_to_image(char *str, mlx_image_t *image, \
uint8_t **charset, size_t xy[2]);
void string_to_image_right(char *str, mlx_image_t *image, \
uint8_t **charset, size_t xy[2]);
void string_to_image_center(char *str, mlx_image_t *image, \
uint8_t **charset, size_t y);
void char_to_image(uint8_t *chr, mlx_image_t *image, \
size_t xy[2], uint32_t color);
// -- MAP VALIDATIONS --
void run_map_validations(char **map_rows, char *map_str);
void validate_filename(char *file);
void validate_empty_lines(char *map);
void validate_map_measurements(char **map);
void validate_map_boundaries(char **map);
void validate_map_content(char *map);
void validate_map_solvability(t_map *map);
void validate_patrol_locations(t_map *map);
// -- PATROLS --
void load_patrols(t_map *map);
void add_new_patrol(t_map *map, size_t pos, char dir);
void add_patrol_to_map(t_map *map, t_patrol *patrol);
int should_be_patrol(char c);
void render_patrols(t_map *map);
size_t patrol_indicator_pos(t_map *map, t_patrol *patrol);
void update_patrol_movement_indicator(t_map *map, t_patrol *patrol);
// -- MAP RENDERING PASSES --
void categorize_map_walls(t_map *map);
void fill_in_background_sprite_indexes(t_map *map);
void render_map(t_map *map);
void render_background_sprite(t_map *map, size_t i, uint8_t **sprites);
void render_pillar(t_map *map, size_t i);
void render_background_pixels(t_map *map);
void render_collectibles(t_map *map);
void render_shadows(t_map *map);
void render_shadow_sprite(t_map *map, size_t i);
void render_player(t_map *map);
void render_patrol_movement_indicators(t_map *map);
// -- GUI helpers --
void render_gui(t_map *map);
void render_gui_static_strings(t_map *map);
void render_gui_dynamic_strings(t_map *map);
void initialize_gui_dynamic_strings(t_map *map);
void update_gui(t_map *map);
void endscreen_hook(void *map_ptr);
void render_endscreen_background(t_map *map, mlx_image_t *image);
void render_victory_screen(t_map *map);
void render_game_over_screen(t_map *map);
// -- Categorization helpers --
void initial_wall_seed(t_map *map);
void recursive_walls(t_map *map);
int neighbors_wall(t_map *map, size_t i);
int can_be_wall(t_map *map, size_t i);
void lava_and_pillars(t_map *map);
void north_walls(t_map *map);
void fill_floors_and_strip_walls(t_map *map);
int is_edge_wall(size_t i, t_map *map);
int floor_or_north_wall(size_t i, t_map *map);
// -- Wall pass helpers --
uint8_t determine_wall_sprite(t_map *map, size_t i);
int check_against_bitmask(uint8_t input, char *mask, int c);
uint8_t cyclical_shift_two(uint8_t in);
void fill_in_north_wall_sprites(t_map *map);
size_t fill_in_north_wall_segment(t_map *map, size_t i);
void decorate_north_wall_segment(t_map *map, size_t i, size_t len);
uint8_t undecorated_north_wall_sprite(void);
uint8_t edge_single(uint8_t surroundings);
uint8_t edge_consecutive(uint8_t surroundings);
uint8_t edge_opposing(uint8_t surroundings);
uint8_t edge_triple(uint8_t surroundings);
uint8_t wall_corner(uint8_t surroundings);
uint8_t wall_single(uint8_t surroundings);
uint8_t wall_opposing(uint8_t surroundings);
uint8_t wall_triple(uint8_t surroundings);
uint8_t wall_corner_edge(uint8_t surroundings);
uint8_t wall_single_edge_lr(uint8_t surroundings);
uint8_t wall_single_edge_l(uint8_t surroundings);
uint8_t wall_single_edge_r(uint8_t surroundings);
// -- Lava pass helpers --
uint8_t determine_lava_sprite(t_map *map, size_t i);
uint8_t match_high_lava_sprites(uint8_t surroundings);
uint8_t match_low_lava_sprites(uint8_t surroundings);
// -- Floor pass helpers --
void fill_in_floors(t_map *map);
uint8_t determine_floor_surroundings(t_map *map, size_t i);
int floor_tile_fits_space(uint8_t surroundings, char *tile);
void fill_in_floor_tile(t_map *map, size_t i, char *tile);
t_floortile *initialize_tile_list(void);
t_floortile *add_tile_to_list(t_floortile **list, char *pattern);
t_floortile *new_tile(char *pattern);
void free_tile_list(t_floortile **list);
// -- Shadow pass helpers --
void determine_shadow_sprites(t_map *map);
void fill_in_floor_shadow(t_map *map, size_t i);
int should_have_shadow(t_map *map, size_t i);
int is_wall(t_map *map, size_t i);
int is_floor_or_lava(t_map *map, size_t i);
void corner_floor_shadow(t_map *map, size_t i);
void small_corner_floor_shadow(t_map *map, size_t i);
void continuous_n_floor_shadow(t_map *map, size_t i);
void ending_n_floor_shadow(t_map *map, size_t i);
void continuous_w_floor_shadow(t_map *map, size_t i);
void ending_w_floor_shadow(t_map *map, size_t i);
// -- Exit helpers --
uint8_t determine_exit_sprite(t_map *map, size_t i);
// -- COLLECTIBLES --
void load_map_collectibles(t_map *map);
void add_collectible_to_map(t_map *map, size_t i);
void clear_collectible_list(t_map *map);
// -- RENDER TOOLS --
size_t render_x_pos(t_map *map, size_t i);
size_t render_y_pos(t_map *map, size_t i);
// -- GAMEPLAY AND ANIMATIONS --
void key_hook(void *map_ptr);
void player_movement_wrapper(t_map *map, char key);
void animate_player(t_map *map, size_t offset);
void try_move_player_up(t_map *map);
void try_move_player_left(t_map *map);
void try_move_player_down(t_map *map);
void try_move_player_right(t_map *map);
void movement_animation_wrapper(t_map *map);
void animate_player_movement_up(t_map *map);
void animate_player_movement_right(t_map *map);
void animate_player_movement_down(t_map *map);
void animate_player_movement_left(t_map *map);
void animate_characters_hook(void *map_ptr);
void animate_background_hook(void *map_ptr);
void mark_sprites_for_animation(t_map *map);
int finish_moving_and_run_checks(t_map *map);
void try_pick_up_collectible(t_map *map, size_t pos);
int try_exit_map(t_map *map);
int player_next_to_patrol(t_map *map);
int game_over(t_map *map, int victory);
void patrol_movement_animation_wrapper(t_map *map);
void update_patrol_movement_direction(t_map *map, t_patrol *patrol);
void update_patrol_facing_offset(t_patrol *patrol);
void animate_patrol_movement_up(t_map *map, t_patrol *patrol);
void animate_patrol_movement_right(t_map *map, t_patrol *patrol);
void animate_patrol_movement_down(t_map *map, t_patrol *patrol);
void animate_patrol_movement_left(t_map *map, t_patrol *patrol);
void idle_animate_patrols(t_map *map, size_t offset);
// -- SPRITE MANAGEMENT --
t_sprite *add_new_sprite(t_map *map, uint8_t **sheet, size_t index);
t_sprite *find_or_create_sprite(t_map *map, uint8_t **sheet, size_t i);
// -- STRUCT FUNCTIONS --
t_map *initialize_map_struct(char **map_array);
void free_map_struct(t_map *map);
void detach_images_from_spritesheets(t_map *map);
void free_linked_lists(t_map *map);
void free_map_collectibles(t_map *map);
// -- HELPERS --
char *join_string_array(char **array);
char *last_string_in_array(char **array);
// -- FREEING/EXIT FUNCTIONS --
void free_array(void **array);
void exit_message(char *msg);
void exit_perror(char *msg);
#endif