#include <SDL2/SDL.h>
-#include <assert.h>
+#include "system/stacktrace.h"
#include <stdio.h>
#include <stdlib.h>
#include "game/level/player/dying_rect.h"
#include "game/level/player/rigid_rect.h"
+#include "game/level/script.h"
#include "goals.h"
#include "math/point.h"
#include "platforms.h"
#include "player.h"
-#include "system/error.h"
+#include "system/line_stream.h"
+#include "system/log.h"
#include "system/lt.h"
+#include "system/nth_alloc.h"
#define PLAYER_WIDTH 25.0f
#define PLAYER_HEIGHT 25.0f
#define PLAYER_SPEED 500.0f
#define PLAYER_JUMP 32000.0f
#define PLAYER_DEATH_DURATION 0.75f
-#define PLAYER_MAX_JUMP_COUNT 2
+#define PLAYER_MAX_JUMP_THRESHOLD 2
typedef enum Player_state {
PLAYER_STATE_ALIVE = 0,
PLAYER_STATE_DYING
} Player_state;
+/* TODO(#633): Player's alive_body should be a body from RigidBodies */
struct Player {
Lt *lt;
Player_state state;
Rigid_rect *alive_body;
Dying_rect *dying_body;
+ Script *script;
- int jump_count;
+ int jump_threshold;
Color color;
Vec checkpoint;
int play_die_cue;
};
-Player *create_player(float x, float y, Color color)
+Player *create_player_from_line_stream(LineStream *line_stream, Broadcast *broadcast)
{
+ trace_assert(line_stream);
+
Lt *lt = create_lt();
if (lt == NULL) {
return NULL;
}
- Player *player = PUSH_LT(lt, malloc(sizeof(Player)), free);
+ Player *player = PUSH_LT(lt, nth_alloc(sizeof(Player)), free);
if (player == NULL) {
- throw_error(ERROR_TYPE_LIBC);
RETURN_LT(lt, NULL);
}
+ player->lt = lt;
- player->state = PLAYER_STATE_ALIVE;
+ float x = 0.0f, y = 0.0f;
+ char colorstr[7];
+
+ if (sscanf(
+ line_stream_next(line_stream),
+ "%f%f%6s",
+ &x, &y, colorstr) == EOF) {
+ log_fail("Could not read player\n");
+ RETURN_LT(lt, NULL);
+ }
+
+ player->script = PUSH_LT(
+ lt,
+ create_script_from_line_stream(line_stream, broadcast),
+ destroy_script);
+ if (player->script == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ const Color color = hexstr(colorstr);
player->alive_body = PUSH_LT(
lt,
RETURN_LT(lt, NULL);
}
- player->lt = lt;
- player->jump_count = 0;
+ player->jump_threshold = 0;
player->color = color;
player->checkpoint = vec(x, y);
player->play_die_cue = 0;
+ player->state = PLAYER_STATE_ALIVE;
return player;
}
-Player *create_player_from_stream(FILE *stream)
-{
- float x = 0.0f, y = 0.0f;
-
- char color[7];
- if (fscanf(stream, "%f%f%6s", &x, &y, color) == EOF) {
- throw_error(ERROR_TYPE_LIBC);
- return NULL;
- }
-
- return create_player(x, y, color_from_hexstr(color));
-}
-
void destroy_player(Player * player)
{
RETURN_LT0(player->lt);
int player_render(const Player * player,
Camera *camera)
{
- assert(player);
- assert(camera);
+ trace_assert(player);
+ trace_assert(camera);
switch (player->state) {
case PLAYER_STATE_ALIVE:
void player_update(Player *player,
float delta_time)
{
- assert(player);
+ trace_assert(player);
switch (player->state) {
case PLAYER_STATE_ALIVE: {
rigid_rect_collide_with_solid(player->alive_body, solid);
if (rigid_rect_touches_ground(player->alive_body)) {
- player->jump_count = 0;
+ player->jump_threshold = 0;
}
}
}
void player_move_left(Player *player)
{
- assert(player);
+ trace_assert(player);
rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
}
void player_move_right(Player *player)
{
- assert(player);
+ trace_assert(player);
rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
}
void player_stop(Player *player)
{
- assert(player);
+ trace_assert(player);
rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
}
void player_jump(Player *player)
{
- assert(player);
- if (player->jump_count < PLAYER_MAX_JUMP_COUNT) {
+ trace_assert(player);
+ if (player->jump_threshold < PLAYER_MAX_JUMP_THRESHOLD) {
rigid_rect_transform_velocity(player->alive_body,
make_mat3x3(1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f));
rigid_rect_apply_force(player->alive_body,
vec(0.0f, -PLAYER_JUMP));
- player->jump_count++;
+ player->jump_threshold++;
+
+ if (script_has_scope_value(player->script, "on-jump")) {
+ script_eval(player->script, "(on-jump)");
+ }
}
}
void player_die(Player *player)
{
- assert(player);
+ trace_assert(player);
if (player->state == PLAYER_STATE_ALIVE) {
const Rect hitbox =
void player_focus_camera(Player *player,
Camera *camera)
{
- assert(player);
- assert(camera);
+ trace_assert(player);
+ trace_assert(camera);
const Rect player_hitbox = rigid_rect_hitbox(player->alive_body);
void player_hide_goals(const Player *player,
Goals *goals)
{
- assert(player);
- assert(goals);
- goals_hide(goals, rigid_rect_hitbox(player->alive_body));
+ trace_assert(player);
+ trace_assert(goals);
+ goals_hide_from_player(goals, rigid_rect_hitbox(player->alive_body));
}
void player_die_from_lava(Player *player,
Rigid_rect *player_rigid_rect(Player *player, const char *id)
{
- assert(player);
- assert(id);
+ trace_assert(player);
+ trace_assert(id);
if (player->state == PLAYER_STATE_ALIVE) {
if (rigid_rect_has_id(player->alive_body, id)) {
return NULL;
}
+
+bool player_overlaps_rect(const Player *player,
+ Rect rect)
+{
+ trace_assert(player);
+
+ return player->state == PLAYER_STATE_ALIVE
+ && rects_overlap(
+ rect, rigid_rect_hitbox(
+ player->alive_body));
+}