2025-10-04 15:53:55 +01:00
|
|
|
#include "../player.h"
|
2025-10-05 18:05:01 +01:00
|
|
|
#include <SDL3/SDL_events.h>
|
2025-10-05 14:42:19 +01:00
|
|
|
#include <SDL3/SDL_keycode.h>
|
2025-10-05 21:05:29 +01:00
|
|
|
#include <stdio.h>
|
2025-10-04 15:53:55 +01:00
|
|
|
|
2025-10-06 17:49:08 +01:00
|
|
|
// @Todo: move/extern these so the npc/bandit can use them
|
|
|
|
|
//
|
|
|
|
|
#define G_OUTFIT_COMPONENT_COUNT 8
|
|
|
|
|
|
|
|
|
|
global_var Str8 __outfit_names[] = {
|
|
|
|
|
Sl("npc_%s_base_%d"),
|
|
|
|
|
Sl("npc_%s_eyes_%d"),
|
|
|
|
|
Sl("npc_%s_face_%d"),
|
|
|
|
|
Sl("npc_%s_hair_%d"),
|
|
|
|
|
Sl("npc_%s_hat_%d"),
|
|
|
|
|
Sl("npc_%s_shirt_%d"),
|
|
|
|
|
Sl("npc_%s_shoes_%d"),
|
|
|
|
|
Sl("npc_%s_trousers_%d")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
global_var U32 __outfit_counts[] = {
|
|
|
|
|
2, // base
|
|
|
|
|
3, // eyes
|
|
|
|
|
5, // face
|
|
|
|
|
4, // hair
|
|
|
|
|
3, // hat
|
|
|
|
|
2, // shirt
|
|
|
|
|
1, // shoes
|
|
|
|
|
2 // trousers
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
global_var U32 __outfit_back_counts[] = {
|
|
|
|
|
2, // base
|
|
|
|
|
0, // eyes
|
|
|
|
|
3, // face
|
|
|
|
|
4, // hair
|
|
|
|
|
3, // hat
|
|
|
|
|
2, // shirt
|
|
|
|
|
1, // shoes
|
|
|
|
|
2 // trousers
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
StaticAssert(ArraySize(__outfit_names) == ArraySize(__outfit_counts));
|
|
|
|
|
|
|
|
|
|
#define OUTFIT_IMG(dir, n) D_ImageHandle(&game->draw, Sf(temp.arena, (const char *) __outfit_names[it].data, #dir, n))
|
|
|
|
|
|
|
|
|
|
void PlayerInit(G_State *game, Player *player) {
|
|
|
|
|
World *world = game->world;
|
|
|
|
|
player->world = world;
|
|
|
|
|
|
2025-10-06 17:55:32 +01:00
|
|
|
player->bulletsLoaded = PLAYER_BULLET_COUNT;
|
|
|
|
|
player->currentArea = WORLD_AREA_OUTSIDE;
|
|
|
|
|
|
|
|
|
|
player->health = 3;
|
|
|
|
|
|
|
|
|
|
player->collision.size.x = 1;
|
|
|
|
|
player->collision.size.x = 2;
|
2025-10-06 17:49:08 +01:00
|
|
|
|
|
|
|
|
G_Outfit *outfit = &player->outfit;
|
|
|
|
|
|
|
|
|
|
D_AnimationInit(&outfit->state, 0, 1, 4, 1.0f / 6.0f);
|
|
|
|
|
|
|
|
|
|
M_TempScope(0, 0) {
|
|
|
|
|
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
|
|
|
|
|
U32 idx = Random_Next(&world->random) % __outfit_counts[it];
|
|
|
|
|
|
|
|
|
|
// We just allow face, hair and hat to default to 0 meaning the player doesn't have one
|
|
|
|
|
if (idx != 0 || it < 2 || it > 4) {
|
|
|
|
|
outfit->front.e[it] = OUTFIT_IMG(front, idx);
|
|
|
|
|
outfit->side.e[it] = OUTFIT_IMG(side, idx);
|
|
|
|
|
|
|
|
|
|
if ((idx + 1) <= __outfit_counts[it]) {
|
|
|
|
|
outfit->back.e[it] = OUTFIT_IMG(back, idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-05 18:05:01 +01:00
|
|
|
void PlayerInput(SDL_Event *event, Player *player)
|
2025-10-04 15:53:55 +01:00
|
|
|
{
|
2025-10-04 17:36:47 +01:00
|
|
|
SDL_KeyboardEvent key = event->key;
|
|
|
|
|
SDL_MouseButtonEvent mouseBtn = event->button;
|
2025-10-05 18:05:01 +01:00
|
|
|
if(event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
|
|
|
|
|
bool val = event->type == SDL_EVENT_KEY_DOWN;
|
|
|
|
|
switch (key.key)
|
|
|
|
|
{
|
|
|
|
|
case SDLK_W:
|
|
|
|
|
{
|
|
|
|
|
player->controls.upDown = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SDLK_A:
|
|
|
|
|
{
|
|
|
|
|
player->controls.leftDown = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SDLK_D:
|
|
|
|
|
{
|
|
|
|
|
player->controls.rightDown = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SDLK_S:
|
|
|
|
|
{
|
|
|
|
|
player->controls.downDown = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-04 17:36:47 +01:00
|
|
|
}
|
2025-10-05 21:05:29 +01:00
|
|
|
if (
|
2025-10-06 17:49:08 +01:00
|
|
|
event->type == SDL_EVENT_MOUSE_BUTTON_DOWN
|
2025-10-05 21:05:29 +01:00
|
|
|
&& mouseBtn.button == SDL_BUTTON_LEFT
|
|
|
|
|
) {
|
|
|
|
|
if(player->bulletsLoaded > 0) {
|
|
|
|
|
// shooting
|
|
|
|
|
player->bulletsLoaded -= 1;
|
|
|
|
|
player->controls.shot = true;
|
2025-10-05 22:35:34 +01:00
|
|
|
player->shotPos = player->world->mouseProjected;
|
|
|
|
|
printf("shot %f %f\n", player->shotPos.x, player->shotPos.y);
|
2025-10-05 21:05:29 +01:00
|
|
|
} else if(player->reloadTimer == 0) {
|
|
|
|
|
player->reloadTimer = PLAYER_RELOAD_TIME;
|
|
|
|
|
printf("reloading\n");
|
|
|
|
|
};
|
2025-10-06 17:49:08 +01:00
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlayerUpdate(F32 delta, Player *player) {
|
2025-10-05 23:36:50 +01:00
|
|
|
player->controls.shot = false;
|
2025-10-05 18:05:01 +01:00
|
|
|
V2f dir = V2F(0, 0);
|
2025-10-06 17:45:58 +01:00
|
|
|
if(player->health == 0){
|
|
|
|
|
printf("dead :(");
|
|
|
|
|
player->health = 3;
|
|
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
if(player->controls.upDown) {
|
|
|
|
|
dir.y -= 1;
|
2025-10-06 17:49:08 +01:00
|
|
|
player->outfit.dir = G_OUTFIT_DIR_BACK;
|
2025-10-04 17:36:47 +01:00
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
if(player->controls.downDown) {
|
|
|
|
|
dir.y += 1;
|
2025-10-06 17:49:08 +01:00
|
|
|
player->outfit.dir = G_OUTFIT_DIR_FRONT;
|
2025-10-04 17:36:47 +01:00
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
if(player->controls.leftDown) {
|
|
|
|
|
dir.x -= 1;
|
2025-10-06 17:49:08 +01:00
|
|
|
player->outfit.dir = G_OUTFIT_DIR_SIDE | G_OUTFIT_DIR_FLIPPED;
|
2025-10-04 17:36:47 +01:00
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
if(player->controls.rightDown) {
|
|
|
|
|
dir.x += 1;
|
2025-10-06 17:49:08 +01:00
|
|
|
player->outfit.dir = G_OUTFIT_DIR_SIDE;
|
2025-10-04 17:36:47 +01:00
|
|
|
}
|
2025-10-06 17:49:08 +01:00
|
|
|
|
|
|
|
|
if (dir.x != 0 || dir.y != 0) {
|
|
|
|
|
D_AnimationUpdate(&player->outfit.state, delta);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
player->outfit.state.index = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-05 21:05:29 +01:00
|
|
|
if(player->reloadTimer > 0) {
|
|
|
|
|
player->reloadTimer-=delta;
|
|
|
|
|
if(player->reloadTimer <= 0) {
|
|
|
|
|
player->bulletsLoaded = PLAYER_BULLET_COUNT;
|
|
|
|
|
player->reloadTimer = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-05 18:05:01 +01:00
|
|
|
dir = V2f_Scale(NormaliseV2F(dir), PLAYER_SPEED*delta);
|
2025-10-06 17:30:49 +01:00
|
|
|
player->collision.pos.x += dir.x;
|
|
|
|
|
player->collision.pos.y += dir.y;
|
2025-10-06 21:07:55 +01:00
|
|
|
for(int i = 0; i < player->world->portalCount; i++) {
|
|
|
|
|
if(AABB_Collide(player->world->portals[0].box, player->collision)) {
|
|
|
|
|
player->currentArea = player->world->portals[0].area;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-04 15:53:55 +01:00
|
|
|
}
|
2025-10-06 17:49:08 +01:00
|
|
|
|
|
|
|
|
void PlayerDraw(D_Context *draw, Player *player) {
|
|
|
|
|
G_Outfit *outfit = &player->outfit;
|
|
|
|
|
|
|
|
|
|
R2f pframe = D_AnimationFrame(&outfit->state);
|
|
|
|
|
|
|
|
|
|
for (U32 it = 0; it < G_OUTFIT_COMPONENT_COUNT; ++it) {
|
|
|
|
|
U32 flipped = (outfit->dir & G_OUTFIT_DIR_FLIPPED) != 0;
|
|
|
|
|
U32 dir = (outfit->dir & ~G_OUTFIT_DIR_FLIPPED);
|
|
|
|
|
|
|
|
|
|
U32 tid = outfit->e[dir].e[it];
|
|
|
|
|
if (tid != 0) {
|
|
|
|
|
U32 flags = D_RECT_UV_ASPECT | (flipped ? D_RECT_FLIP_X : 0);
|
2025-10-06 17:55:32 +01:00
|
|
|
D_Rect(draw, player->collision.pos.x, player->collision.pos.y, .texture = tid, .uv = pframe, .flags = flags);
|
2025-10-06 17:49:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|