suicmez/game/client.c
2025-12-20 18:30:21 +05:30

393 lines
18 KiB
C

#include "libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
void* gc_alloc(const TypeInfo* type, size_t size);
void gc_init(void);
void gc_shutdown(void);
// Helper for allocating arrays
static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) {
void* ptr = gc_alloc(type, elem_size * len);
if (init_data) memcpy(ptr, init_data, elem_size * len);
return ptr;
}
// Helper for allocating structs
static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) {
void* ptr = gc_alloc(type, size);
if (init_data) memcpy(ptr, init_data, size);
return ptr;
}
;
;
;
struct GameState {
struct SuicVec3 cam_pos;
float yaw;
float pitch;
struct SuicVec3 prev_body_pos;
struct SuicVec3 current_target_body;
float interp_timer;
float recoil_yaw;
float recoil_pitch;
float cross_spread;
bool scoped;
float fire_cooldown;
int shots_in_burst;
float burst_reset_timer;
int client_tick;
struct SuicDirectionalLight light;
};
;
;
static const uint8_t sui_bitmap_SuicVec3[] = { 0, 0, 0 };
static const TypeInfo sui_typeinfo_SuicVec3 = {
.field_count = 3,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_SuicVec3
};
static const uint8_t sui_bitmap_SuicColor[] = { 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_SuicColor = {
.field_count = 4,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_SuicColor
};
static const uint8_t sui_bitmap_SuicDirectionalLight[] = { 0, 0, 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_SuicDirectionalLight = {
.field_count = 6,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_SuicDirectionalLight
};
static const uint8_t sui_bitmap_GameState[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_GameState = {
.field_count = 15,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_GameState
};
void suic_game_init(struct GameState* game_state, char* username, char* server_ip, int port);
void suic_game_shutdown(void);
void suic_game_handle_input(struct GameState* game_state, float dt);
void suic_game_update(struct GameState* game_state, float dt);
void suic_game_render(struct GameState* game_state);
int suic_main(void);
const float PISTOL_FIRE_RATE = 4.000000;
const float RIFLE_FIRE_RATE = 12.000000;
const float RECOIL_RETURN = 18.000000;
const float CROSS_RETURN = 14.000000;
const float PISTOL_KICK_PITCH = 0.010000;
const float PISTOL_KICK_YAW = 0.004000;
const float RIFLE_KICK_PITCH = 0.018000;
const float RIFLE_KICK_YAW = 0.010000;
const float PISTOL_CROSS_KICK = 2.000000;
const float RIFLE_CROSS_KICK = 4.000000;
const float PISTOL_SPRAY_GROW = 0.400000;
const float RIFLE_SPRAY_GROW = 1.200000;
const float BURST_RESET_TIME = 0.180000;
void suic_game_init(struct GameState* game_state, char* username, char* server_ip, int port) {
suic_terrain_init();
suic_net_init(server_ip, port);
suic_net_send_hello(username);
suic_disable_cursor();
}
void suic_game_shutdown(void) {
suic_terrain_cleanup();
suic_net_shutdown();
}
void suic_game_handle_input(struct GameState* game_state, float dt) {
(((*game_state))).client_tick = ((((((*game_state))).client_tick)) + ((1)));
(((*game_state))).fire_cooldown = ((((((*game_state))).fire_cooldown)) - ((dt)));
if (((((((*game_state))).fire_cooldown)) < ((0.000000)))) {
(((*game_state))).fire_cooldown = 0.000000;
}
(((*game_state))).burst_reset_timer = ((((((*game_state))).burst_reset_timer)) - ((dt)));
if (((((((*game_state))).burst_reset_timer)) <= ((0.000000)))) {
(((*game_state))).shots_in_burst = 0;
}
float k = (((1.000000)) - ((expf((((((-RECOIL_RETURN)))) * ((dt)))))));
(((*game_state))).recoil_yaw = ((((((*game_state))).recoil_yaw)) + ((((((((0.000000)) - (((((*game_state))).recoil_yaw))))) * ((k))))));
(((*game_state))).recoil_pitch = ((((((*game_state))).recoil_pitch)) + ((((((((0.000000)) - (((((*game_state))).recoil_pitch))))) * ((k))))));
float k2 = (((1.000000)) - ((expf((((((-CROSS_RETURN)))) * ((dt)))))));
(((*game_state))).cross_spread = ((((((*game_state))).cross_spread)) + ((((((((0.000000)) - (((((*game_state))).cross_spread))))) * ((k2))))));
if (((((((*game_state))).cross_spread)) < ((0.010000)))) {
(((*game_state))).cross_spread = 0.000000;
}
struct suic_vec2 md = suic_get_mouse_delta();
float sens = 0.002500;
(((*game_state))).yaw = ((((((*game_state))).yaw)) - ((((((md).x)) * ((sens))))));
(((*game_state))).pitch = ((((((*game_state))).pitch)) - ((((((md).y)) * ((sens))))));
if (((((((*game_state))).pitch)) < ((((-1.500000)))))) {
(((*game_state))).pitch = ((-1.500000));
}
if (((((((*game_state))).pitch)) > ((1.500000)))) {
(((*game_state))).pitch = 1.500000;
}
float move_x = 0.000000;
float move_z = 0.000000;
if (suic_is_key_down(65)) {
move_x = (((move_x)) - ((1.000000)));
}
if (suic_is_key_down(68)) {
move_x = (((move_x)) + ((1.000000)));
}
if (suic_is_key_down(87)) {
move_z = (((move_z)) + ((1.000000)));
}
if (suic_is_key_down(83)) {
move_z = (((move_z)) - ((1.000000)));
}
int buttons = 0;
if (suic_is_key_pressed(82)) {
buttons = (((buttons)) | ((SUIC_BTN_RELOAD)));
}
if (suic_is_key_pressed(49)) {
buttons = (((buttons)) | ((SUIC_BTN_SWITCH_PISTOL)));
}
if (suic_is_key_pressed(50)) {
buttons = (((buttons)) | ((SUIC_BTN_SWITCH_RIFLE)));
}
if (suic_is_key_pressed(70)) {
buttons = (((buttons)) | ((SUIC_BTN_PICK)));
}
if (suic_is_key_pressed(72)) {
buttons = (((buttons)) | ((SUIC_BTN_USE_MEDKIT)));
}
if (suic_is_key_pressed(32)) {
buttons = (((buttons)) | ((SUIC_BTN_JUMP)));
}
if (suic_is_key_pressed(90)) {
(((*game_state))).scoped = ((!(((*game_state))).scoped));
}
int my_id = suic_net_get_my_id();
float view_yaw = ((((((*game_state))).yaw)) + (((((*game_state))).recoil_yaw)));
float view_pitch = ((((((*game_state))).pitch)) + (((((*game_state))).recoil_pitch)));
float clamped_view_pitch = view_pitch;
if ((((clamped_view_pitch)) < ((((-1.500000)))))) {
clamped_view_pitch = ((-1.500000));
}
if ((((clamped_view_pitch)) > ((1.500000)))) {
clamped_view_pitch = 1.500000;
}
if ((((my_id)) != ((255)))) {
suic_net_send_input(my_id, (((*game_state))).client_tick, move_x, move_z, view_yaw, clamped_view_pitch, buttons);
}
if (((((((((((((my_id)) != ((255))))) && ((suic_is_mouse_button_down(0)))))) && ((((((((*game_state))).fire_cooldown)) <= ((0.000000)))))))) && ((suic_net_player_present(my_id))))) {
int wpn = suic_net_player_weapon(my_id);
float rate = RIFLE_FIRE_RATE;
if ((((wpn)) == ((SUIC_WEAPON_PISTOL)))) {
rate = PISTOL_FIRE_RATE;
}
(((*game_state))).fire_cooldown = (((1.000000)) / ((rate)));
(((*game_state))).shots_in_burst = ((((((*game_state))).shots_in_burst)) + ((1)));
(((*game_state))).burst_reset_timer = BURST_RESET_TIME;
if ((((wpn)) == ((SUIC_WEAPON_PISTOL)))) {
(((*game_state))).recoil_pitch = ((((((*game_state))).recoil_pitch)) + ((PISTOL_KICK_PITCH)));
(((*game_state))).recoil_yaw = ((((((*game_state))).recoil_yaw)) + (((((((((float) GetRandomValue(((-1000)), 1000))) / ((1000.000000))))) * ((PISTOL_KICK_YAW))))));
(((*game_state))).cross_spread = (((((((((*game_state))).cross_spread)) + ((PISTOL_CROSS_KICK))))) + ((((((float) (((*game_state))).shots_in_burst)) * ((PISTOL_SPRAY_GROW))))));
}
if ((((wpn)) == ((SUIC_WEAPON_RIFLE)))) {
(((*game_state))).recoil_pitch = ((((((*game_state))).recoil_pitch)) + ((RIFLE_KICK_PITCH)));
(((*game_state))).recoil_yaw = ((((((*game_state))).recoil_yaw)) + (((((((((float) GetRandomValue(((-1000)), 1000))) / ((1000.000000))))) * ((RIFLE_KICK_YAW))))));
(((*game_state))).cross_spread = (((((((((*game_state))).cross_spread)) + ((RIFLE_CROSS_KICK))))) + ((((((float) (((*game_state))).shots_in_burst)) * ((RIFLE_SPRAY_GROW))))));
}
suic_net_send_shoot(my_id, (((*game_state))).client_tick);
}
}
void suic_game_update(struct GameState* game_state, float dt) {
suic_net_poll();
int my_id = suic_net_get_my_id();
if (((((((my_id)) != ((255))))) && ((suic_net_player_present(my_id))))) {
(((*game_state))).prev_body_pos = (((*game_state))).current_target_body;
(((*game_state))).current_target_body = suic_v3(suic_net_player_x(my_id), suic_net_player_y(my_id), suic_net_player_z(my_id));
(((*game_state))).interp_timer = 0.000000;
}
if (((((((my_id)) != ((255))))) && ((suic_net_player_present(my_id))))) {
float interp_factor = ((((((*game_state))).interp_timer)) / (((((1.000000)) / ((20.000000))))));
if ((((interp_factor)) > ((1.000000)))) {
interp_factor = 1.000000;
}
struct SuicVec3 interp_body = suic_v3_add(suic_v3_mul((((*game_state))).prev_body_pos, (((1.000000)) - ((interp_factor)))), suic_v3_mul((((*game_state))).current_target_body, interp_factor));
((((*game_state))).cam_pos).x = (interp_body).x;
((((*game_state))).cam_pos).y = ((((interp_body).y)) + ((1.000000)));
((((*game_state))).cam_pos).z = ((((interp_body).z)) + ((0.000100)));
float terrain_h = suic_terrain_height(((((*game_state))).cam_pos).x, ((((*game_state))).cam_pos).z);
((((*game_state))).cam_pos).y = fmaxf(((((*game_state))).cam_pos).y, (((terrain_h)) + ((1.500000))));
}
(((*game_state))).interp_timer = ((((((*game_state))).interp_timer)) + ((dt)));
if ((((my_id)) != ((255)))) {
float view_yaw = ((((((*game_state))).yaw)) + (((((*game_state))).recoil_yaw)));
float view_pitch = ((((((*game_state))).pitch)) + (((((*game_state))).recoil_pitch)));
struct SuicVec3 forward = suic_v3((((sinf(view_yaw))) * ((cosf(view_pitch)))), sinf(view_pitch), (((cosf(view_yaw))) * ((cosf(view_pitch)))));
(((*game_state))).cam_pos = suic_v3_add((((*game_state))).cam_pos, suic_v3_mul(forward, 0.300000));
((((*game_state))).cam_pos).y = (((((((*game_state))).cam_pos).y)) - ((0.200000)));
}
float terrain_h = suic_terrain_height(((((*game_state))).cam_pos).x, ((((*game_state))).cam_pos).z);
((((*game_state))).cam_pos).y = fmaxf(((((*game_state))).cam_pos).y, (((terrain_h)) + ((1.500000))));
}
void suic_game_render(struct GameState* game_state) {
int sw = GetScreenWidth();
int sh = GetScreenHeight();
int my_id = suic_net_get_my_id();
float view_yaw = ((((((*game_state))).yaw)) + (((((*game_state))).recoil_yaw)));
float view_pitch = ((((((*game_state))).pitch)) + (((((*game_state))).recoil_pitch)));
float clamped_view_pitch = view_pitch;
if ((((clamped_view_pitch)) < ((((-1.500000)))))) {
clamped_view_pitch = ((-1.500000));
}
if ((((clamped_view_pitch)) > ((1.500000)))) {
clamped_view_pitch = 1.500000;
}
struct SuicVec3 forward = suic_v3((((sinf(view_yaw))) * ((cosf(clamped_view_pitch)))), sinf(clamped_view_pitch), (((cosf(view_yaw))) * ((cosf(clamped_view_pitch)))));
float fov = 75.000000;
if ((((*game_state))).scoped) {
fov = 30.000000;
}
suic_begin_mode3d(((((*game_state))).cam_pos).x, ((((*game_state))).cam_pos).y, ((((*game_state))).cam_pos).z, (((((((*game_state))).cam_pos).x)) + (((forward).x))), (((((((*game_state))).cam_pos).y)) + (((forward).y))), (((((((*game_state))).cam_pos).z)) + (((forward).z))), 0.000000, 1.000000, 0.000000, fov, 0);
suic_terrain_draw((((*game_state))).cam_pos);
float border_size = (((SUIC_TERRAIN_MAX)) - ((SUIC_TERRAIN_MIN)));
suic_draw_cube(0.000000, 0.000000, 0.000000, border_size, 1000.000000, border_size, 255, 0, 0, 100);
int i = 0;
while ((((i)) < ((SUIC_NET_MAX_ITEMS)))) {
if (suic_net_item_present(i)) {
int ic_r = 220;
int ic_g = 220;
int ic_b = 220;
int item_type = suic_net_item_type(i);
if ((((item_type)) == ((SUIC_ITEM_MEDKIT)))) {
ic_r = 120;
ic_g = 255;
ic_b = 120;
}
if ((((item_type)) == ((SUIC_ITEM_AMMO_PISTOL)))) {
ic_r = 255;
ic_g = 220;
ic_b = 120;
}
if ((((item_type)) == ((SUIC_ITEM_AMMO_RIFLE)))) {
ic_r = 255;
ic_g = 180;
ic_b = 120;
}
struct SuicVec3 item_pos = suic_v3(suic_net_item_x(i), suic_net_item_y(i), suic_net_item_z(i));
struct SuicVec3 item_normal = suic_v3(0.000000, 1.000000, 0.000000);
struct SuicColor base_color = ((struct SuicColor){ .r = (uint8_t) ic_r, .g = (uint8_t) ic_g, .b = (uint8_t) ic_b, .a = 255 });
struct SuicColor lit_color = suic_light_apply_shadows(base_color, item_normal, item_pos, ((&(((*game_state))).light)));
suic_draw_sphere((item_pos).x, (item_pos).y, (item_pos).z, 0.300000, (int) (lit_color).r, (int) (lit_color).g, (int) (lit_color).b, (int) (lit_color).a);
}
i = (((i)) + ((1)));
}
i = 0;
while ((((i)) < ((SUIC_NET_MAX_PLAYERS)))) {
if (suic_net_player_present(i)) {
float interp_factor = ((((((*game_state))).interp_timer)) / (((((1.000000)) / ((20.000000))))));
if ((((interp_factor)) > ((1.000000)))) {
interp_factor = 1.000000;
}
struct SuicVec3 prev = suic_v3(suic_net_player_prev_x(i), suic_net_player_prev_y(i), suic_net_player_prev_z(i));
struct SuicVec3 curr = suic_v3(suic_net_player_x(i), suic_net_player_y(i), suic_net_player_z(i));
struct SuicVec3 p = suic_v3_add(suic_v3_mul(prev, (((1.000000)) - ((interp_factor)))), suic_v3_mul(curr, interp_factor));
int c_r = 255;
int c_g = 80;
int c_b = 80;
if ((((i)) == ((my_id)))) {
c_r = 80;
c_g = 180;
c_b = 255;
}
if (((!suic_net_player_alive(i)))) {
c_r = 120;
c_g = 120;
c_b = 120;
}
struct SuicVec3 player_normal = suic_v3(0.000000, 1.000000, 0.000000);
struct SuicColor base_color = ((struct SuicColor){ .r = (uint8_t) c_r, .g = (uint8_t) c_g, .b = (uint8_t) c_b, .a = 255 });
struct SuicColor lit_color = suic_light_apply_shadows(base_color, player_normal, p, ((&(((*game_state))).light)));
suic_draw_capsule((p).x, ((((p).y)) - ((0.500000))), (p).z, (p).x, ((((p).y)) + ((0.500000))), (p).z, 0.350000, 8, 8, (int) (lit_color).r, (int) (lit_color).g, (int) (lit_color).b, (int) (lit_color).a);
}
i = (((i)) + ((1)));
}
suic_end_mode3d();
i = 0;
while ((((i)) < ((SUIC_NET_MAX_PLAYERS)))) {
if (suic_net_player_present(i)) {
float interp_factor = ((((((*game_state))).interp_timer)) / (((((1.000000)) / ((20.000000))))));
if ((((interp_factor)) > ((1.000000)))) {
interp_factor = 1.000000;
}
struct SuicVec3 prev = suic_v3(suic_net_player_prev_x(i), suic_net_player_prev_y(i), suic_net_player_prev_z(i));
struct SuicVec3 curr = suic_v3(suic_net_player_x(i), suic_net_player_y(i), suic_net_player_z(i));
struct SuicVec3 p = suic_v3_add(suic_v3_mul(prev, (((1.000000)) - ((interp_factor)))), suic_v3_mul(curr, interp_factor));
suic_ui_draw_nameplate(sw, sh, (p).x, (p).y, (p).z, suic_net_player_username(i), (((i)) == ((my_id))), ((((*game_state))).cam_pos).x, ((((*game_state))).cam_pos).y, ((((*game_state))).cam_pos).z, (((((((*game_state))).cam_pos).x)) + (((forward).x))), (((((((*game_state))).cam_pos).y)) + (((forward).y))), (((((((*game_state))).cam_pos).z)) + (((forward).z))));
}
i = (((i)) + ((1)));
}
if (((((((my_id)) == ((255))))) || ((((!suic_net_player_present(my_id))))))) {
suic_draw_text(suic_alloc_array(NULL, sizeof(char), 8, "Offline"), 10, 10, 20, 255, 255, 255, 255);
}
if (((((((my_id)) != ((255))))) && ((suic_net_player_present(my_id))))) {
int weapon = suic_net_player_weapon(my_id);
int mag = suic_net_player_rifle_mag(my_id);
int reserve = suic_net_player_rifle_ammo(my_id);
if ((((weapon)) == ((SUIC_WEAPON_PISTOL)))) {
mag = suic_net_player_pistol_mag(my_id);
reserve = suic_net_player_pistol_ammo(my_id);
}
suic_ui_draw_hud(suic_net_player_hp(my_id), weapon, mag, reserve, suic_net_player_medkits(my_id), suic_net_player_reload_time(my_id));
}
suic_draw_fps((((sw)) - ((90))), 10);
suic_ui_draw_room_state(sw, sh, suic_net_room_state(), suic_net_countdown(), suic_net_winner_name());
suic_ui_draw_crosshair(sw, sh, (((*game_state))).cross_spread, (((*game_state))).scoped);
}
int suic_main(void) {
struct SuicVec3 zero_vec = ((struct SuicVec3){ .x = 0.000000, .y = 0.000000, .z = 0.000000 });
struct SuicDirectionalLight default_light = ((struct SuicDirectionalLight){ .direction = zero_vec, .color = zero_vec, .intensity = 0.000000, .ambientIntensity = 0.000000, .shadowBias = 0.000000, .shadowIntensity = 0.000000 });
struct GameState game_state = ((struct GameState){ .cam_pos = ((struct SuicVec3){ .x = 0.000000, .y = 5.000000, .z = 6.000000 }), .yaw = 0.000000, .pitch = 0.000000, .prev_body_pos = ((struct SuicVec3){ .x = 0.000000, .y = 5.000000, .z = 6.000000 }), .current_target_body = ((struct SuicVec3){ .x = 0.000000, .y = 5.000000, .z = 6.000000 }), .interp_timer = 0.000000, .recoil_yaw = 0.000000, .recoil_pitch = 0.000000, .cross_spread = 0.000000, .scoped = false, .fire_cooldown = 0.000000, .shots_in_burst = 0, .burst_reset_timer = 0.000000, .client_tick = 0, .light = default_light });
int screen_w = 1280;
int screen_h = 720;
suic_init_window(screen_w, screen_h, suic_alloc_array(NULL, sizeof(char), 5, "Soup"));
suic_set_target_fps(120);
suic_disable_cursor();
(game_state).light = suic_light_create_default();
char* username = suic_alloc_array(NULL, sizeof(char), 1, "");
suic_ui_username_prompt(username, SUIC_NET_USERNAME_MAX);
suic_game_init(((&game_state)), username, suic_alloc_array(NULL, sizeof(char), 15, "24.240.181.107"), 27015);
while ((((suic_window_should_close())) == ((false)))) {
float dt = suic_get_frame_time();
suic_game_handle_input(((&game_state)), dt);
suic_game_update(((&game_state)), dt);
suic_begin_drawing();
suic_clear_background(135, 206, 235, 255);
suic_game_render(((&game_state)));
suic_end_drawing();
}
suic_game_shutdown();
suic_close_window();
return 0;
}
int main(int argc, char* argv[]) {
// Initialize GC
gc_init();
// init globals
// init event loop
int result = suic_main();
// Shutdown GC
gc_shutdown();
return result;
}