Compare commits

..

No commits in common. "2d9857483035bdb1674daba913a2b3bff78b742d" and "57d8c7a2b7708838ba59c96f51ee5806868ef7a6" have entirely different histories.

6 changed files with 37 additions and 127 deletions

Binary file not shown.

View file

@ -1,3 +1,4 @@
// game/client.c - SMOOTH TERRAIN VERSION WITH DIRECTIONAL LIGHT & SHADOWS
#include "raylib.h"
#include <math.h>
#include <stdint.h>
@ -179,8 +180,6 @@ float get_terrain_height(float x, float z) {
#define TERRAIN_SIZE 256
#define TERRAIN_SCALE 1.0f
#define TERRAIN_MIN (-TERRAIN_SIZE * TERRAIN_SCALE / 2.0f)
#define TERRAIN_MAX (TERRAIN_SIZE * TERRAIN_SCALE / 2.0f)
static Mesh generate_terrain_mesh(void) {
int size = TERRAIN_SIZE;
@ -395,9 +394,6 @@ static Vector3 v3_add(Vector3 a, Vector3 b) {
static Vector3 v3_sub(Vector3 a, Vector3 b) {
return v3(a.x - b.x, a.y - b.y, a.z - b.z);
}
static Vector3 v3_mul(Vector3 a, float s) {
return v3(a.x * s, a.y * s, a.z * s);
}
static float v3_dot(Vector3 a, Vector3 b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
@ -589,7 +585,6 @@ typedef struct MsgRoomState {
typedef struct RemotePlayer {
int present, alive, hp;
Vector3 pos;
Vector3 prevPos;
float yaw, pitch;
uint8_t weapon;
int16_t pistolMag, rifleMag, pistolAmmo, rifleAmmo, medkits;
@ -722,10 +717,6 @@ int main(void) {
Vector3 camPos = v3(0, 5.0f, 6);
float yaw = 0.0f, pitch = 0.0f;
Vector3 prevBodyPos = v3(0, 5.0f, 6);
Vector3 currentTargetBody = v3(0, 5.0f, 6);
float interpTimer = 0.0f;
float recoilYaw = 0.0f, recoilPitch = 0.0f, crossSpread = 0.0f;
int scoped = 0;
float fireCooldown = 0.0f;
@ -802,7 +793,6 @@ int main(void) {
continue;
RemotePlayer *p = &rp[ps->id];
p->prevPos = p->pos;
p->present = 1;
p->alive = ps->alive;
p->hp = ps->hp;
@ -821,9 +811,14 @@ int main(void) {
}
if (myId != 255 && rp[myId].present) {
prevBodyPos = currentTargetBody;
currentTargetBody = rp[myId].pos;
interpTimer = 0.0f;
Vector3 body = rp[myId].pos;
camPos.x = body.x;
camPos.y = body.y + 1.0f;
camPos.z = body.z + 0.0001f;
// Prevent camera from clipping into terrain
float terrain_h = get_terrain_height(camPos.x, camPos.z);
camPos.y = fmaxf(camPos.y, terrain_h + 1.5f);
}
} else if (type == MSG_ITEMS && n >= (int)sizeof(MsgItems)) {
MsgItems *m = (MsgItems *)buf;
@ -848,23 +843,6 @@ int main(void) {
}
}
// Interpolate camera position
if (myId != 255 && rp[myId].present) {
float interpFactor = interpTimer / (1.0f / 20.0f);
if (interpFactor > 1.0f)
interpFactor = 1.0f;
Vector3 interpBody = v3_add(v3_mul(prevBodyPos, 1.0f - interpFactor),
v3_mul(currentTargetBody, interpFactor));
camPos.x = interpBody.x;
camPos.y = interpBody.y + 1.0f;
camPos.z = interpBody.z + 0.0001f;
// Prevent camera from clipping into terrain
float terrain_h = get_terrain_height(camPos.x, camPos.z);
camPos.y = fmaxf(camPos.y, terrain_h + 1.5f);
}
interpTimer += dt;
Vector2 md = GetMouseDelta();
const float sens = 0.0025f;
yaw -= md.x * sens;
@ -953,14 +931,6 @@ int main(void) {
Vector3 forward = v3(sinf(viewYaw) * cosf(viewPitch), sinf(viewPitch),
cosf(viewYaw) * cosf(viewPitch));
// Offset camera position: 0.3m in front, 0.2m below
camPos = v3_add(camPos, v3_mul(forward, 0.3f));
camPos.y -= 0.2f;
// Ensure camera doesn't clip into terrain after offset
float terrain_h = get_terrain_height(camPos.x, camPos.z);
camPos.y = fmaxf(camPos.y, terrain_h + 1.5f);
Camera3D cam = {0};
cam.position = camPos;
cam.target = v3_add(camPos, forward);
@ -1007,10 +977,6 @@ int main(void) {
(Color){80, 140, 70, 255};
DrawModel(terrainModel, (Vector3){0, 0, 0}, 1.0f, WHITE);
// Draw border
float borderSize = TERRAIN_MAX - TERRAIN_MIN;
DrawCube((Vector3){0, 0, 0}, borderSize, 1000, borderSize, (Color){255, 0, 0, 100});
// Items with basic lighting (no shader for now to keep it simple)
for (int i = 0; i < MAX_ITEMS; i++) {
if (!wi[i].present)
@ -1034,11 +1000,7 @@ int main(void) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!rp[i].present)
continue;
float interpFactor = interpTimer / (1.0f / 20.0f);
if (interpFactor > 1.0f)
interpFactor = 1.0f;
Vector3 p = v3_add(v3_mul(rp[i].prevPos, 1.0f - interpFactor),
v3_mul(rp[i].pos, interpFactor));
Vector3 p = rp[i].pos;
Color c =
(i == myId) ? (Color){80, 180, 255, 255} : (Color){255, 80, 80, 255};
if (!rp[i].alive)
@ -1058,12 +1020,7 @@ int main(void) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!rp[i].present || !rp[i].username[0])
continue;
float interpFactor = interpTimer / (1.0f / 20.0f);
if (interpFactor > 1.0f)
interpFactor = 1.0f;
Vector3 p = v3_add(v3_mul(rp[i].prevPos, 1.0f - interpFactor),
v3_mul(rp[i].pos, interpFactor));
Vector3 head = v3(p.x, p.y + 1.2f, p.z);
Vector3 head = v3(rp[i].pos.x, rp[i].pos.y + 1.2f, rp[i].pos.z);
Vector3 camForward = v3_norm(v3_sub(cam.target, cam.position));
Vector3 toHead = v3_sub(head, cam.position);
if (v3_dot(camForward, toHead) <= 0.0f)
@ -1124,18 +1081,18 @@ int main(void) {
// Room state overlay
if (roomState == 0) { // Waiting
DrawRectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, (Color){0, 0, 0, 200});
DrawRectangle(sw / 2 - 150, sh / 2 - 50, 300, 100, (Color){0, 0, 0, 200});
DrawText("WAITING FOR PLAYERS", sw / 2 - 120, sh / 2 - 30, 24, RAYWHITE);
DrawText("Need at least 2 players", sw / 2 - 100, sh / 2 - 5, 18,
(Color){200, 200, 200, 255});
} else if (roomState == 1) { // Counting down
DrawRectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, (Color){0, 0, 0, 200});
DrawRectangle(sw / 2 - 150, sh / 2 - 50, 300, 100, (Color){0, 0, 0, 200});
DrawText("GAME STARTING SOON", sw / 2 - 120, sh / 2 - 30, 24,
(Color){255, 255, 80, 255});
DrawText(TextFormat("%.1f seconds", countdownRemaining), sw / 2 - 60,
sh / 2 - 5, 20, RAYWHITE);
} else if (roomState == 3) { // Finished
DrawRectangle(sw / 2 - 200, sh / 2 - 50, 450, 100, (Color){0, 0, 0, 200});
DrawRectangle(sw / 2 - 200, sh / 2 - 50, 400, 100, (Color){0, 0, 0, 200});
DrawText("GAME FINISHED", sw / 2 - 80, sh / 2 - 30, 28,
(Color){255, 80, 80, 255});
if (winnerName[0]) {

Binary file not shown.

1
game/libfishsoup Symbolic link
View file

@ -0,0 +1 @@
../libfishsoup

Binary file not shown.

View file

@ -1,3 +1,4 @@
// game/server.c - SMOOTH TERRAIN VERSION
#include <math.h>
#include <stdint.h>
#include <stdio.h>
@ -153,8 +154,6 @@ float get_terrain_height(float x, float z) {
#define TERRAIN_SIZE 256
#define TERRAIN_SCALE 1.0f
#define TERRAIN_MIN (-TERRAIN_SIZE * TERRAIN_SCALE / 2.0f)
#define TERRAIN_MAX (TERRAIN_SIZE * TERRAIN_SCALE / 2.0f)
static dReal *gHeightData = NULL;
static dGeomID gTerrainGeom = NULL;
@ -300,7 +299,6 @@ typedef struct Player {
uint32_t rng;
float reloadTimer;
int reloadWeapon;
float borderDamageTimer;
dBodyID body;
dGeomID geom;
} Player;
@ -469,8 +467,6 @@ static void player_ode_create(Player *p, int spawnIndex) {
dGeomSetBody(p->geom, p->body);
dGeomSetCategoryBits(p->geom, CAT_PLAYER);
dGeomSetCollideBits(p->geom, CAT_WORLD | CAT_PLAYER);
p->borderDamageTimer = 0.0f;
}
static void player_ode_destroy(Player *p) {
@ -993,71 +989,27 @@ int main(void) {
}
}
for (int i = 0; i < MAX_PLAYERS; i++) {
Player *p = &players[i];
if (!p->inUse || !p->alive)
continue;
for (int i = 0; i < MAX_PLAYERS; i++) {
Player *p = &players[i];
if (!p->inUse || !p->alive)
continue;
const dReal *lvel = dBodyGetLinearVel(p->body);
const dReal *avel = dBodyGetAngularVel(p->body);
const dReal *lvel = dBodyGetLinearVel(p->body);
const dReal *avel = dBodyGetAngularVel(p->body);
float dx = p->moveX, dz = p->moveZ;
float len = sqrtf(dx * dx + dz * dz);
if (len > 1e-6f) {
dx /= len;
dz /= len;
}
float dx = p->moveX, dz = p->moveZ;
float len = sqrtf(dx * dx + dz * dz);
if (len > 1e-6f) {
dx /= len;
dz /= len;
}
float speed = 10.0f;
float fx = sinf(p->yaw) * dz - cosf(p->yaw) * dx;
float fz = cosf(p->yaw) * dz + sinf(p->yaw) * dx;
dBodySetLinearVel(p->body, fx * speed, lvel[1], fz * speed);
dBodySetAngularVel(p->body, avel[0], 0, avel[2]);
}
// Border damage
for (int i = 0; i < MAX_PLAYERS; i++) {
Player *p = &players[i];
if (!p->inUse || !p->alive)
continue;
const dReal *pos = dBodyGetPosition(p->body);
float px = (float)pos[0], pz = (float)pos[2];
if (px < TERRAIN_MIN || px > TERRAIN_MAX || pz < TERRAIN_MIN || pz > TERRAIN_MAX) {
p->borderDamageTimer += DT;
if (p->borderDamageTimer >= 0.5f) {
p->borderDamageTimer -= 0.5f;
p->hp -= 1;
if (p->hp <= 0) {
p->hp = 0;
p->alive = 0;
// Drop loot as in shooting death
const dReal *pos2 = dBodyGetPosition(p->body);
float x = (float)pos2[0], z = (float)pos2[2];
if (p->pistolAmmo > 0) {
int qty = p->pistolAmmo;
if (qty > 12) qty = 12;
item_spawn(ITEM_AMMO_PISTOL, qty, x + frand_signed(&p->rng) * 2.0f, z + frand_signed(&p->rng) * 2.0f);
p->pistolAmmo -= qty;
}
if (p->rifleAmmo > 0) {
int qty = p->rifleAmmo;
if (qty > 30) qty = 30;
item_spawn(ITEM_AMMO_RIFLE, qty, x + frand_signed(&p->rng) * 2.0f, z + frand_signed(&p->rng) * 2.0f);
p->rifleAmmo -= qty;
}
if (p->medkits > 0) {
int qty = p->medkits;
if (qty > 2) qty = 2;
item_spawn(ITEM_MEDKIT, qty, x + frand_signed(&p->rng) * 2.0f, z + frand_signed(&p->rng) * 2.0f);
p->medkits -= qty;
}
printf("Player %d died from border damage and dropped loot\n", i);
}
}
} else {
p->borderDamageTimer = 0.0f;
}
}
float speed = 10.0f;
float fx = sinf(p->yaw) * dz - cosf(p->yaw) * dx;
float fz = cosf(p->yaw) * dz + sinf(p->yaw) * dx;
dBodySetLinearVel(p->body, fx * speed, lvel[1], fz * speed);
dBodySetAngularVel(p->body, avel[0], 0, avel[2]);
}
MsgSnapshot snap = {0};
snap.type = MSG_SNAPSHOT;