163 lines
6.7 KiB
C
163 lines
6.7 KiB
C
#include "suic_ui.h"
|
|
#include "suic_net.h"
|
|
#include "raylib.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
/* ===== 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);
|
|
}
|