#include "suic_ui.h" #include "suic_net.h" #include "raylib.h" #include #include #include /* ===== USERNAME PROMPT ===== */ void suic_ui_username_prompt(char* outName, int maxLen) { memset(outName, 0, maxLen); while (!WindowShouldClose()) { int ch = GetCharPressed(); while (ch > 0) { int len = (int)strlen(outName); if (ch >= 32 && ch <= 126) { if (len < maxLen - 1) { outName[len] = (char)ch; outName[len + 1] = '\0'; } } ch = GetCharPressed(); } if (IsKeyPressed(KEY_BACKSPACE)) { int len = (int)strlen(outName); if (len > 0) outName[len - 1] = '\0'; } if (IsKeyPressed(KEY_ENTER) && strlen(outName) > 0) return; BeginDrawing(); ClearBackground((Color){20, 24, 32, 255}); DrawText("Enter username (press ENTER):", 60, 80, 28, RAYWHITE); DrawRectangle(60, 130, 420, 48, (Color){40, 48, 64, 255}); DrawRectangleLines(60, 130, 420, 48, (Color){120, 140, 170, 255}); DrawText(outName[0] ? outName : "_", 72, 142, 24, (Color){230, 230, 240, 255}); EndDrawing(); } } /* ===== HUD ===== */ void suic_ui_draw_hud(int hp, int weapon, int mag, int reserve, int medkits, int reloadTimeLeft) { int sw = GetScreenWidth(); int sh = GetScreenHeight(); /* Health panel */ DrawRectangle(10, 10, 280, 110, (Color){0, 0, 0, 120}); DrawText("HP", 20, 20, 20, RAYWHITE); int healthBarWidth = (hp * 220) / 100; Color healthColor = (hp > 60) ? (Color){80, 255, 80, 120} : (hp > 30) ? (Color){255, 200, 80, 120} : (Color){255, 80, 80, 120}; DrawRectangle(20, 45, 220, 20, (Color){40, 40, 40, 255}); DrawRectangle(20, 45, healthBarWidth, 20, healthColor); DrawText(TextFormat("%d", hp), 250, 47, 18, RAYWHITE); DrawText(TextFormat("Medkits: %d (H to use)", medkits), 20, 75, 18, (medkits > 0) ? (Color){120, 255, 120, 120} : (Color){120, 120, 120, 120}); DrawText("1=Pistol 2=Rifle R=Reload F=Pick SPACE=Jump", 20, 95, 12, (Color){150, 150, 150, 150}); /* Weapon panel */ const char* weaponName = (weapon == SUIC_WEAPON_PISTOL) ? "PISTOL" : "RIFLE"; Color weaponColor = (weapon == SUIC_WEAPON_PISTOL) ? (Color){100, 200, 255, 255} : (Color){255, 150, 100, 255}; DrawRectangle(sw - 260, sh - 120, 250, 110, (Color){0, 0, 0, 180}); DrawText(weaponName, sw - 250, sh - 110, 28, weaponColor); DrawText(TextFormat("%d", mag), sw - 250, sh - 75, 40, RAYWHITE); DrawText(TextFormat("/ %d", reserve), sw - 140, sh - 65, 24, (Color){180, 180, 180, 255}); if (reloadTimeLeft > 0) DrawText("RELOADING...", sw - 250, sh - 30, 20, (Color){255, 200, 80, 255}); else if (mag == 0) DrawText("RELOAD!", sw - 250, sh - 30, 20, (Color){255, 80, 80, 255}); } /* ===== CROSSHAIR ===== */ void suic_ui_draw_crosshair(int screenW, int screenH, float spread, bool scoped) { int cx = screenW / 2, cy = screenH / 2; int gap = scoped ? 2 : 6 + (int)spread; int len = scoped ? 5 : 10; int thick = 2; Color col = (Color){240, 240, 245, 220}; DrawRectangle(cx - gap - len, cy - thick / 2, len, thick, col); DrawRectangle(cx + gap, cy - thick / 2, len, thick, col); DrawRectangle(cx - thick / 2, cy - gap - len, thick, len, col); DrawRectangle(cx - thick / 2, cy + gap, thick, len, col); DrawCircleLines(cx, cy, scoped ? 1.5f : 3.0f, (Color){240, 240, 245, 160}); } /* ===== ROOM STATE ===== */ void suic_ui_draw_room_state(int screenW, int screenH, int state, float countdown, const char* winnerName) { if (state == 0) { /* Waiting */ DrawRectangle(screenW / 2 - 150, screenH / 2 - 50, 350, 100, (Color){0, 0, 0, 200}); DrawText("WAITING FOR PLAYERS", screenW / 2 - 120, screenH / 2 - 30, 24, RAYWHITE); DrawText("Need at least 2 players", screenW / 2 - 100, screenH / 2 - 5, 18, (Color){200, 200, 200, 255}); } else if (state == 1) { /* Counting down */ DrawRectangle(screenW / 2 - 150, screenH / 2 - 50, 350, 100, (Color){0, 0, 0, 200}); DrawText("GAME STARTING SOON", screenW / 2 - 120, screenH / 2 - 30, 24, (Color){255, 255, 80, 255}); DrawText(TextFormat("%.1f seconds", countdown), screenW / 2 - 60, screenH / 2 - 5, 20, RAYWHITE); } else if (state == 3) { /* Finished */ DrawRectangle(screenW / 2 - 200, screenH / 2 - 50, 450, 100, (Color){0, 0, 0, 200}); DrawText("GAME FINISHED", screenW / 2 - 80, screenH / 2 - 30, 28, (Color){255, 80, 80, 255}); if (winnerName && winnerName[0]) { DrawText(TextFormat("Winner: %s", winnerName), screenW / 2 - 100, screenH / 2 - 5, 24, (Color){255, 255, 80, 255}); } else { DrawText("No winner", screenW / 2 - 50, screenH / 2 - 5, 24, RAYWHITE); } } } /* ===== NAMEPLATES ===== */ void suic_ui_draw_nameplate(int screenW, int screenH, float worldX, float worldY, float worldZ, const char* username, bool isLocalPlayer, float camPosX, float camPosY, float camPosZ, float camTargetX, float camTargetY, float camTargetZ) { if (!username || !username[0]) return; Vector3 head = {worldX, worldY + 1.2f, worldZ}; Vector3 camPos = {camPosX, camPosY, camPosZ}; Vector3 camTarget = {camTargetX, camTargetY, camTargetZ}; /* Check if in front of camera */ Vector3 camForward = {camTarget.x - camPos.x, camTarget.y - camPos.y, camTarget.z - camPos.z}; float len = sqrtf(camForward.x * camForward.x + camForward.y * camForward.y + camForward.z * camForward.z); if (len > 0) { camForward.x /= len; camForward.y /= len; camForward.z /= len; } Vector3 toHead = {head.x - camPos.x, head.y - camPos.y, head.z - camPos.z}; float dot = camForward.x * toHead.x + camForward.y * toHead.y + camForward.z * toHead.z; if (dot <= 0.0f) return; Camera3D cam = {0}; cam.position = camPos; cam.target = camTarget; cam.up = (Vector3){0, 1, 0}; cam.fovy = 75.0f; cam.projection = CAMERA_PERSPECTIVE; Vector2 s = GetWorldToScreen(head, cam); if (s.x < -200 || s.x > screenW + 200 || s.y < -200 || s.y > screenH + 200) return; int fontSize = 18; int w = MeasureText(username, fontSize); Color tc = isLocalPlayer ? (Color){180, 230, 255, 255} : RAYWHITE; DrawText(username, (int)(s.x - w / 2), (int)(s.y - fontSize), fontSize, tc); }