6 #include "game/level/player/dying_rect.h"
7 #include "game/level/player/rigid_rect.h"
8 #include "game/level/script.h"
10 #include "math/point.h"
11 #include "platforms.h"
13 #include "system/line_stream.h"
14 #include "system/log.h"
15 #include "system/lt.h"
16 #include "system/nth_alloc.h"
18 #define PLAYER_WIDTH 25.0f
19 #define PLAYER_HEIGHT 25.0f
20 #define PLAYER_SPEED 500.0f
21 #define PLAYER_JUMP 32000.0f
22 #define PLAYER_DEATH_DURATION 0.75f
23 #define PLAYER_MAX_JUMP_THRESHOLD 2
25 typedef enum Player_state {
26 PLAYER_STATE_ALIVE = 0,
34 Rigid_rect *alive_body;
35 Dying_rect *dying_body;
46 Player *create_player_from_line_stream(LineStream *line_stream, Level *level)
56 Player *player = PUSH_LT(lt, nth_alloc(sizeof(Player)), free);
62 float x = 0.0f, y = 0.0f;
66 line_stream_next(line_stream),
68 &x, &y, colorstr) == EOF) {
69 log_fail("Could not read player\n");
73 player->script = PUSH_LT(
75 create_script_from_line_stream(line_stream, level),
77 if (player->script == NULL) {
81 const Color color = hexstr(colorstr);
83 player->alive_body = PUSH_LT(
86 rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
90 if (player->alive_body == NULL) {
94 player->dying_body = PUSH_LT(
98 PLAYER_DEATH_DURATION),
100 if (player->dying_body == NULL) {
104 player->jump_threshold = 0;
105 player->color = color;
106 player->checkpoint = vec(x, y);
107 player->play_die_cue = 0;
108 player->state = PLAYER_STATE_ALIVE;
113 void destroy_player(Player * player)
115 RETURN_LT0(player->lt);
118 Solid_ref player_as_solid(Player *player)
122 .ptr = (void*) player
128 int player_render(const Player * player,
134 switch (player->state) {
135 case PLAYER_STATE_ALIVE:
136 return rigid_rect_render(player->alive_body, camera);
138 case PLAYER_STATE_DYING:
139 return dying_rect_render(player->dying_body, camera);
147 void player_update(Player *player,
152 switch (player->state) {
153 case PLAYER_STATE_ALIVE: {
154 rigid_rect_update(player->alive_body, delta_time);
156 const Rect hitbox = rigid_rect_hitbox(player->alive_body);
158 if (hitbox.y > 1000.0f) {
163 case PLAYER_STATE_DYING: {
164 dying_rect_update(player->dying_body, delta_time);
166 if (dying_rect_is_dead(player->dying_body)) {
167 rigid_rect_transform_velocity(
169 make_mat3x3(0.0f, 0.0f, 0.0f,
172 rigid_rect_teleport_to(player->alive_body, player->checkpoint);
173 player->state = PLAYER_STATE_ALIVE;
181 void player_collide_with_solid(Player *player, Solid_ref solid)
183 if (player->state == PLAYER_STATE_ALIVE) {
184 rigid_rect_collide_with_solid(player->alive_body, solid);
186 if (rigid_rect_touches_ground(player->alive_body)) {
187 player->jump_threshold = 0;
192 void player_move_left(Player *player)
195 rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
198 void player_move_right(Player *player)
202 rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
205 void player_stop(Player *player)
209 rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
212 void player_jump(Player *player)
215 if (player->jump_threshold < PLAYER_MAX_JUMP_THRESHOLD) {
216 rigid_rect_transform_velocity(player->alive_body,
217 make_mat3x3(1.0f, 0.0f, 0.0f,
220 rigid_rect_apply_force(player->alive_body,
221 vec(0.0f, -PLAYER_JUMP));
222 player->jump_threshold++;
224 if (script_has_scope_value(player->script, "on-jump")) {
225 script_eval(player->script, "(on-jump)");
230 void player_die(Player *player)
234 if (player->state == PLAYER_STATE_ALIVE) {
236 rigid_rect_hitbox(player->alive_body);
238 player->play_die_cue = 1;
239 dying_rect_start_dying(player->dying_body, vec(hitbox.x, hitbox.y));
240 player->state = PLAYER_STATE_DYING;
244 void player_focus_camera(Player *player,
250 const Rect player_hitbox = rigid_rect_hitbox(player->alive_body);
255 vec(player_hitbox.x, player_hitbox.y),
256 vec(0.0f, -player_hitbox.h * 0.5f)));
259 void player_hide_goals(const Player *player,
264 goals_hide_from_player(goals, rigid_rect_hitbox(player->alive_body));
267 void player_die_from_lava(Player *player,
270 if (lava_overlaps_rect(lava, rigid_rect_hitbox(player->alive_body))) {
275 void player_checkpoint(Player *player, Vec checkpoint)
277 player->checkpoint = checkpoint;
280 int player_sound(Player *player,
281 Sound_samples *sound_samples)
283 if (player->play_die_cue) {
284 player->play_die_cue = 0;
286 if (sound_samples_play_sound(sound_samples, 0, 0) < 0) {
294 void player_touches_rect_sides(Player *player,
296 int sides[RECT_SIDE_N])
298 if (player->state == PLAYER_STATE_ALIVE) {
299 rigid_rect_touches_rect_sides(player->alive_body, object, sides);
303 void player_apply_force(Player *player, Vec force)
305 if (player->state == PLAYER_STATE_ALIVE) {
306 rigid_rect_apply_force(player->alive_body, force);
310 Rigid_rect *player_rigid_rect(Player *player, const char *id)
315 if (player->state == PLAYER_STATE_ALIVE) {
316 if (rigid_rect_has_id(player->alive_body, id)) {
317 return player->alive_body;
324 bool player_overlaps_rect(const Player *player,
329 return player->state == PLAYER_STATE_ALIVE
331 rect, rigid_rect_hitbox(
332 player->alive_body));