#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/line_stream.h"
+#include "system/log.h"
#include "system/lt.h"
#include "system/nth_alloc.h"
-#include "system/log.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_from_line_stream(LineStream *line_stream)
+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, nth_alloc(sizeof(Player)), free);
+ if (player == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ player->lt = lt;
+
float x = 0.0f, y = 0.0f;
char colorstr[7];
"%f%f%6s",
&x, &y, colorstr) == EOF) {
log_fail("Could not read player\n");
- return NULL;
- }
-
- const Color color = hexstr(colorstr);
-
- Lt *lt = create_lt();
-
- if (lt == NULL) {
- return NULL;
+ RETURN_LT(lt, NULL);
}
- Player *player = PUSH_LT(lt, nth_alloc(sizeof(Player)), free);
- if (player == NULL) {
+ player->script = PUSH_LT(
+ lt,
+ create_script_from_line_stream(line_stream, broadcast),
+ destroy_script);
+ if (player->script == NULL) {
RETURN_LT(lt, NULL);
}
- player->state = PLAYER_STATE_ALIVE;
+ 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;
}
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);
+ trace_assert(player);
+ trace_assert(goals);
goals_hide_from_player(goals, rigid_rect_hitbox(player->alive_body));
}
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)) {
bool player_overlaps_rect(const Player *player,
Rect rect)
{
- assert(player);
+ trace_assert(player);
return player->state == PLAYER_STATE_ALIVE
&& rects_overlap(