285 lines
8.0 KiB
C
285 lines
8.0 KiB
C
#include "ent_impl.h"
|
|
#include "constants.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "raymath.h"
|
|
|
|
#define N_PLAYER_SPRITES 12
|
|
enum PlayerSpriteEnum
|
|
{
|
|
SPR_PLAYER_STAND = 0,
|
|
SPR_PLAYER_RUN,
|
|
SPR_PLAYER_JUMP,
|
|
SPR_PLAYER_FALL,
|
|
SPR_PLAYER_LADDER,
|
|
SPR_PLAYER_CROUCH,
|
|
SPR_PLAYER_CRMOVE,
|
|
SPR_PLAYER_SWIM,
|
|
SPR_PLAYER_USWIM,
|
|
SPR_PLAYER_DSWIM,
|
|
SPR_PLAYER_DEAD,
|
|
SPR_PLAYER_ENTER,
|
|
};
|
|
|
|
static SpriteRenderInfo_t player_sprite_map[N_PLAYER_SPRITES] = {0};
|
|
|
|
static unsigned int player_sprite_transition_func(Entity_t* ent)
|
|
{
|
|
CTransform_t* p_ctrans = get_component(ent, CTRANSFORM_COMP_T);
|
|
CMovementState_t* p_move = get_component(ent, CMOVEMENTSTATE_T);
|
|
CSprite_t* p_spr = get_component(ent, CSPRITE_T);
|
|
CPlayerState_t* p_plr = get_component(ent, CPLAYERSTATE_T);
|
|
|
|
if (p_ctrans->velocity.x > 0) p_spr->flip_x = true;
|
|
else if (p_ctrans->velocity.x < 0) p_spr->flip_x = false;
|
|
|
|
p_spr->pause = false;
|
|
|
|
if (p_move->ground_state & 1)
|
|
{
|
|
if (Vector2LengthSqr(p_ctrans->velocity) > 1000.0f)
|
|
{
|
|
return (p_plr->is_crouch) ? SPR_PLAYER_CRMOVE : SPR_PLAYER_RUN;
|
|
}
|
|
else
|
|
{
|
|
return (p_plr->is_crouch) ? SPR_PLAYER_CROUCH : SPR_PLAYER_STAND;
|
|
}
|
|
}
|
|
else if (p_plr->ladder_state)
|
|
{
|
|
p_spr->pause = Vector2LengthSqr(p_ctrans->velocity) < 10.0f;
|
|
return SPR_PLAYER_LADDER;
|
|
}
|
|
else if (p_move->water_state & 1)
|
|
{
|
|
if (p_ctrans->velocity.y > 50) return SPR_PLAYER_DSWIM;
|
|
|
|
if (p_ctrans->velocity.y < -50) return SPR_PLAYER_USWIM;
|
|
|
|
return SPR_PLAYER_SWIM;
|
|
}
|
|
return (p_ctrans->velocity.y < 0) ? SPR_PLAYER_JUMP : SPR_PLAYER_FALL;
|
|
}
|
|
|
|
Entity_t* create_player(EntityManager_t* ent_manager)
|
|
{
|
|
Entity_t* p_ent = add_entity(ent_manager, PLAYER_ENT_TAG);
|
|
if (p_ent == NULL) return NULL;
|
|
|
|
CBBox_t* p_bbox = add_component(p_ent, CBBOX_COMP_T);
|
|
|
|
set_bbox(p_bbox, PLAYER_WIDTH, PLAYER_HEIGHT);
|
|
CTransform_t* p_ct = add_component(p_ent, CTRANSFORM_COMP_T);
|
|
p_ct->active = true;
|
|
p_ct->shape_factor = (Vector2){1, 1};
|
|
|
|
CJump_t* p_cjump = add_component(p_ent, CJUMP_COMP_T);
|
|
p_cjump->jump_speed = 680;
|
|
p_cjump->jumps = 1;
|
|
p_cjump->max_jumps = 1;
|
|
p_cjump->jump_ready = true;
|
|
add_component(p_ent, CPLAYERSTATE_T);
|
|
add_component(p_ent, CTILECOORD_COMP_T);
|
|
|
|
CMovementState_t* p_move = add_component(p_ent, CMOVEMENTSTATE_T);
|
|
p_move->ground_state |= 3;
|
|
CHitBoxes_t* p_hitbox = add_component(p_ent, CHITBOXES_T);
|
|
p_hitbox->n_boxes = 2;
|
|
p_hitbox->boxes[0] = (Rectangle) {
|
|
.x = 0,
|
|
.y = -2,
|
|
.width = p_bbox->size.x,
|
|
.height = p_bbox->size.y + 4,
|
|
};
|
|
p_hitbox->boxes[1] = (Rectangle) {
|
|
.x = -2,
|
|
.y = 0,
|
|
.width = p_bbox->size.x + 4,
|
|
.height = p_bbox->size.y,
|
|
};
|
|
p_hitbox->atk = 2;
|
|
CHurtbox_t* p_hurtbox = add_component(p_ent, CHURTBOX_T);
|
|
p_hurtbox->size = p_bbox->size;
|
|
|
|
CAirTimer_t* p_air = add_component(p_ent, CAIRTIMER_T);
|
|
p_air->max_count = 10;
|
|
p_air->curr_count = 10;
|
|
p_air->max_ftimer = 0.9f;
|
|
p_air->decay_rate = 1.0f;
|
|
|
|
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
|
p_cspr->sprites = player_sprite_map;
|
|
p_cspr->transition_func = &player_sprite_transition_func;
|
|
|
|
CEmitter_t* p_emitter = add_component(p_ent, CEMITTER_T);
|
|
p_emitter->offset = (Vector2){7,0};
|
|
|
|
add_component(p_ent, CSQUISHABLE_T);
|
|
|
|
return p_ent;
|
|
}
|
|
|
|
Entity_t* create_dead_player(EntityManager_t* ent_manager)
|
|
{
|
|
Entity_t* p_ent = add_entity(ent_manager, NO_ENT_TAG);
|
|
if (p_ent == NULL) return NULL;
|
|
|
|
CTransform_t* p_ct = add_component(p_ent, CTRANSFORM_COMP_T);
|
|
p_ct->active = true;
|
|
p_ct->shape_factor = (Vector2){1, 1};
|
|
p_ct->velocity.y = -450;
|
|
|
|
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
|
p_cspr->sprites = player_sprite_map;
|
|
p_cspr->current_idx = SPR_PLAYER_DEAD;
|
|
|
|
add_component(p_ent, CMOVEMENTSTATE_T);
|
|
|
|
return p_ent;
|
|
}
|
|
|
|
static unsigned int player_finish_transition_func(Entity_t* ent)
|
|
{
|
|
CSprite_t* p_spr = get_component(ent, CSPRITE_T);
|
|
// Due to index-from-0
|
|
if (p_spr->current_frame == p_spr->sprites[p_spr->current_idx].sprite->frame_count - 1)
|
|
{
|
|
p_spr->pause = true;
|
|
//remove_entity(ent->manager, ent->m_id);
|
|
}
|
|
return p_spr->current_idx;
|
|
}
|
|
|
|
Entity_t* create_player_finish(EntityManager_t* ent_manager)
|
|
{
|
|
Entity_t* p_ent = add_entity(ent_manager, NO_ENT_TAG);
|
|
if (p_ent == NULL) return NULL;
|
|
|
|
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
|
|
p_cspr->sprites = player_sprite_map;
|
|
p_cspr->current_idx = SPR_PLAYER_ENTER;
|
|
p_cspr->transition_func = &player_finish_transition_func;
|
|
|
|
add_component(p_ent, CTILECOORD_COMP_T);
|
|
|
|
CLifeTimer_t* p_clifetimer = add_component(p_ent, CLIFETIMER_T);
|
|
p_clifetimer->life_time = 0.9f;
|
|
return p_ent;
|
|
}
|
|
|
|
static AnchorPoint_t parse_anchor_symbol(const char symbol[2])
|
|
{
|
|
if (symbol[0] == 't')
|
|
{
|
|
if (symbol[1] == 'l') return AP_TOP_LEFT;
|
|
if (symbol[1] == 'c') return AP_TOP_CENTER;
|
|
if (symbol[1] == 'r') return AP_TOP_RIGHT;
|
|
}
|
|
else if (symbol[0] == 'm')
|
|
{
|
|
if (symbol[1] == 'l') return AP_MID_LEFT;
|
|
if (symbol[1] == 'c') return AP_MID_CENTER;
|
|
if (symbol[1] == 'r') return AP_MID_RIGHT;
|
|
}
|
|
else if (symbol[0] == 'b')
|
|
{
|
|
if (symbol[1] == 'l') return AP_BOT_LEFT;
|
|
if (symbol[1] == 'c') return AP_BOT_CENTER;
|
|
if (symbol[1] == 'r') return AP_BOT_RIGHT;
|
|
}
|
|
|
|
return AP_TOP_LEFT;
|
|
}
|
|
|
|
static bool init_player_file(FILE* in_file, Assets_t* assets)
|
|
{
|
|
static bool already_init = false;
|
|
|
|
if (already_init) return false;
|
|
|
|
char buffer[256];
|
|
char* tmp;
|
|
size_t line_num = 0;
|
|
uint8_t i = 0;
|
|
while (true)
|
|
{
|
|
tmp = fgets(buffer, 256, in_file);
|
|
if (tmp == NULL) break;
|
|
tmp[strcspn(tmp, "\r\n")] = '\0';
|
|
|
|
if (i == N_PLAYER_SPRITES) break;
|
|
|
|
char* name = strtok(buffer, ":");
|
|
char* info_str = strtok(NULL, ":");
|
|
if (name == NULL || info_str == NULL) return false;
|
|
|
|
while(*name == ' ' || *name == '\t') name++;
|
|
while(*info_str == ' ' || *info_str == '\t') info_str++;
|
|
|
|
Vector2 offset;
|
|
char src_ap_symbol[3];
|
|
char dest_ap_symbol[3];
|
|
int data_count = sscanf(
|
|
info_str, "%f,%f,%2s,%2s",
|
|
&offset.x, &offset.y, src_ap_symbol, dest_ap_symbol
|
|
);
|
|
if (data_count != 4)
|
|
{
|
|
printf("Unable to parse info for player at line %lu\n", line_num);
|
|
return false;
|
|
}
|
|
Sprite_t* spr = get_sprite(assets, name);
|
|
spr->anchor = Vector2Scale(spr->frame_size, 0.5f);
|
|
player_sprite_map[i].sprite = spr;
|
|
player_sprite_map[i].offset = offset;
|
|
player_sprite_map[i].src_anchor = parse_anchor_symbol(src_ap_symbol);
|
|
player_sprite_map[i].dest_anchor = parse_anchor_symbol(dest_ap_symbol);
|
|
i++;
|
|
}
|
|
already_init = true;
|
|
return true;
|
|
}
|
|
|
|
bool init_player_creation(const char* info_file, Assets_t* assets)
|
|
{
|
|
FILE* in_file = fopen(info_file, "r");
|
|
if (in_file == NULL)
|
|
{
|
|
printf("Unable to open file %s\n", info_file);
|
|
return false;
|
|
}
|
|
bool okay = init_player_file(in_file, assets);
|
|
fclose(in_file);
|
|
|
|
return okay;
|
|
}
|
|
|
|
bool init_player_creation_rres(const char* rres_fname, const char* file, Assets_t* assets)
|
|
{
|
|
RresFileInfo_t rres_file;
|
|
rres_file.dir = rresLoadCentralDirectory(rres_fname);
|
|
rres_file.fname = rres_fname;
|
|
|
|
if (rres_file.dir.count == 0)
|
|
{
|
|
puts("Empty central directory");
|
|
return false;
|
|
}
|
|
|
|
unsigned int res_id = rresGetResourceId(rres_file.dir, file);
|
|
rresResourceChunk chunk = rresLoadResourceChunk(rres_file.fname, res_id);
|
|
|
|
bool okay = false;
|
|
if (chunk.info.id == res_id)
|
|
{
|
|
FILE* in_file = fmemopen(chunk.data.raw, chunk.info.baseSize, "rb");
|
|
okay = init_player_file(in_file, assets);
|
|
fclose(in_file);
|
|
}
|
|
|
|
rresUnloadResourceChunk(chunk);
|
|
rresUnloadCentralDirectory(rres_file.dir);
|
|
return okay;
|
|
}
|