From d1782e1265373426c01208486493988d1bf6ac81 Mon Sep 17 00:00:00 2001 From: Masashi Date: Thu, 18 Dec 2025 22:28:54 +0530 Subject: [PATCH] gam --- game/client | Bin 34344 -> 34416 bytes game/client.c | 68 ++++++++++++++----- game/server | Bin 35296 -> 39600 bytes game/server.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 221 insertions(+), 27 deletions(-) diff --git a/game/client b/game/client index 87018d34770d6938fa5887bc54b4dbc8377fa81a..0c15c789d7d2a3dd201ea555dbb94f2d64ed0f1f 100755 GIT binary patch delta 11723 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 yl^m#xCq7U86&#l^h{d%5AQP;60i(BmNgw0J{$W delta 11072 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[i].qty; wi[i].pos = v3(m->items[i].x, m->items[i].y, m->items[i].z); } + } else if (type == MSG_ROOM_STATE && n >= (int)sizeof(MsgRoomState)) { + const MsgRoomState *rs = (const MsgRoomState *)buf; + roomState = rs->state; + countdownRemaining = rs->countdownRemaining; + memset(winnerName, 0, USERNAME_MAX); + if (rs->winnerId < 255) { + strncpy(winnerName, rs->winnerName, USERNAME_MAX - 1); + } } } @@ -1068,6 +1079,30 @@ int main(void) { DrawFPS(sw - 90, 10); + // Room state overlay + if (roomState == 0) { // Waiting + 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, 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, 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]) { + DrawText(TextFormat("Winner: %s", winnerName), sw / 2 - 100, sh / 2 - 5, + 24, (Color){255, 255, 80, 255}); + } else { + DrawText("No winner", sw / 2 - 50, sh / 2 - 5, 24, RAYWHITE); + } + } + // Crosshair { int cx = sw / 2, cy = sh / 2; @@ -1078,7 +1113,8 @@ int main(void) { 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}); + DrawCircleLines(cx, cy, scoped ? 1.5f : 3.0f, + (Color){240, 240, 245, 160}); } EndDrawing(); diff --git a/game/server b/game/server index 8a2b6891af6ba32baeea0bca61915852cf8ffe89..03a07482de264198b4064e3ed8b5d116efeb1c4b 100755 GIT binary patch literal 39600 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 literal 35296 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 diff --git a/game/server.c b/game/server.c index 28bceea..b3c61b9 100644 --- a/game/server.c +++ b/game/server.c @@ -29,7 +29,7 @@ typedef int socklen_t; #define MAX_PLAYERS 16 #define USERNAME_MAX 16 -#define TICK_HZ 30 +#define TICK_HZ 20 #define DT (1.0f / (float)TICK_HZ) #define WEAPON_PISTOL 0 @@ -49,11 +49,15 @@ typedef int socklen_t; #define BTN_USE_MEDKIT (1u << 4) #define BTN_JUMP (1u << 5) +#define ROOM_STATE_WAITING 0 +#define ROOM_STATE_COUNTING_DOWN 1 +#define ROOM_STATE_RUNNING 2 +#define ROOM_STATE_FINISHED 3 + #define CAT_WORLD (1u << 0) #define CAT_PLAYER (1u << 1) #define CAT_ITEM (1u << 2) -// ============== SIMPLEX NOISE ============== static const uint8_t perm[512] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, @@ -167,7 +171,6 @@ static void generate_smooth_terrain(void) { printf("Generated smooth heightmap terrain %dx%d\n", size, size); } -// ============== END SIMPLEX NOISE ============== static double now_seconds(void) { #ifdef _WIN32 @@ -204,7 +207,8 @@ typedef enum MsgType : uint8_t { MSG_INPUT = 3, MSG_SNAPSHOT = 4, MSG_SHOOT = 5, - MSG_ITEMS = 6 + MSG_ITEMS = 6, + MSG_ROOM_STATE = 7 } MsgType; typedef struct MsgHello { @@ -263,6 +267,14 @@ typedef struct MsgItems { uint8_t count; ItemNet items[MAX_ITEMS]; } MsgItems; + +typedef struct MsgRoomState { + uint8_t type; + uint8_t state; + float countdownRemaining; + uint8_t winnerId; + char winnerName[USERNAME_MAX]; +} MsgRoomState; #pragma pack(pop) typedef struct Item { @@ -291,6 +303,13 @@ typedef struct Player { dGeomID geom; } Player; +typedef struct RoomState { + int state; + double countdownEndTime; + int winnerId; + int playerCount; +} RoomState; + static int addr_equal(const struct sockaddr_in *a, const struct sockaddr_in *b) { return (a->sin_family == b->sin_family) && (a->sin_port == b->sin_port) && @@ -319,6 +338,7 @@ static dSpaceID gSpace; static dJointGroupID gContactGroup; static Item gItems[MAX_ITEMS]; static uint16_t gNextItemId = 1; +static RoomState gRoomState; static void item_destroy(Item *it) { if (it->geom) { @@ -397,10 +417,25 @@ static void ode_init_world(void) { dGeomSetCategoryBits(gTerrainGeom, CAT_WORLD); dGeomSetCollideBits(gTerrainGeom, CAT_PLAYER); - item_spawn(ITEM_MEDKIT, 1, 10.0f, 10.0f); - item_spawn(ITEM_MEDKIT, 1, -15.0f, 20.0f); - item_spawn(ITEM_AMMO_RIFLE, 30, 5.0f, -10.0f); - item_spawn(ITEM_AMMO_PISTOL, 12, -10.0f, -15.0f); + // Spawn initial random loot + for (int i = 0; i < 4; i++) { + float x = (float)(rand() % 200 - 100); + float z = (float)(rand() % 200 - 100); + uint8_t type; + int qty; + int type_idx = rand() % 3; + if (type_idx == 0) { + type = ITEM_MEDKIT; + qty = 1; + } else if (type_idx == 1) { + type = ITEM_AMMO_PISTOL; + qty = 10 + (rand() % 6); + } else { + type = ITEM_AMMO_RIFLE; + qty = 20 + (rand() % 11); + } + item_spawn(type, qty, x, z); + } } static void ode_shutdown_world(void) { @@ -422,8 +457,9 @@ static void player_ode_create(Player *p, int spawnIndex) { dBodySetLinearDamping(p->body, 0.05); dBodySetAngularDamping(p->body, 0.99); - float sx = (float)(spawnIndex * 4 - 8); - float sz = (float)(spawnIndex * 3 - 6); + // Random spawn position + float sx = (float)(rand() % 200 - 100); // -100 to 99 + float sz = (float)(rand() % 200 - 100); float sy = get_terrain_height(sx, sz) + 3.0f; dBodySetPosition(p->body, sx, sy, sz); @@ -553,6 +589,12 @@ int main(void) { srand((unsigned)time(NULL)); + // Initialize room state + gRoomState.state = ROOM_STATE_WAITING; + gRoomState.countdownEndTime = 0.0; + gRoomState.winnerId = -1; + gRoomState.playerCount = 0; + ode_init_world(); int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -612,6 +654,9 @@ int main(void) { continue; if (pid < 0) { + // Only allow joining if room is not running + if (gRoomState.state == ROOM_STATE_RUNNING) + continue; for (int i = 0; i < MAX_PLAYERS; i++) if (!players[i].inUse) { pid = i; @@ -631,6 +676,7 @@ int main(void) { p->medkits = 2; p->rng = 0xA341316Cu ^ (uint32_t)(i * 2654435761u); player_ode_create(p, i); + gRoomState.playerCount++; printf("Player %d joined as '%s'\n", pid, p->username); break; } @@ -715,7 +761,7 @@ int main(void) { } else if (type == MSG_SHOOT && n >= (int)sizeof(MsgShoot)) { const MsgShoot *m = (const MsgShoot *)buf; if (pid >= 0 && m->playerId == (uint8_t)pid && players[pid].inUse && - players[pid].alive) { + players[pid].alive && gRoomState.state == ROOM_STATE_RUNNING) { Player *sh = &players[pid]; const double now = now_seconds(); double fireInterval = @@ -783,6 +829,37 @@ int main(void) { if (players[victim].hp <= 0) { players[victim].hp = 0; players[victim].alive = 0; + // Drop loot + const dReal *pos = dBodyGetPosition(players[victim].body); + float x = (float)pos[0], z = (float)pos[2]; + if (players[victim].pistolAmmo > 0) { + int qty = players[victim].pistolAmmo; + if (qty > 12) + qty = 12; // Max per drop + item_spawn(ITEM_AMMO_PISTOL, qty, + x + frand_signed(&players[victim].rng) * 2.0f, + z + frand_signed(&players[victim].rng) * 2.0f); + players[victim].pistolAmmo -= qty; + } + if (players[victim].rifleAmmo > 0) { + int qty = players[victim].rifleAmmo; + if (qty > 30) + qty = 30; + item_spawn(ITEM_AMMO_RIFLE, qty, + x + frand_signed(&players[victim].rng) * 2.0f, + z + frand_signed(&players[victim].rng) * 2.0f); + players[victim].rifleAmmo -= qty; + } + if (players[victim].medkits > 0) { + int qty = players[victim].medkits; + if (qty > 2) + qty = 2; + item_spawn(ITEM_MEDKIT, qty, + x + frand_signed(&players[victim].rng) * 2.0f, + z + frand_signed(&players[victim].rng) * 2.0f); + players[victim].medkits -= qty; + } + printf("Player %d died and dropped loot\n", victim); } } } @@ -790,6 +867,66 @@ int main(void) { } } + // Room state management + { + double now = now_seconds(); + if (gRoomState.state == ROOM_STATE_WAITING) { + // Count active players + int activePlayers = 0; + for (int i = 0; i < MAX_PLAYERS; i++) { + if (players[i].inUse) + activePlayers++; + } + gRoomState.playerCount = activePlayers; + if (activePlayers >= 2) { + gRoomState.state = ROOM_STATE_COUNTING_DOWN; + gRoomState.countdownEndTime = now + 10.0; // 10 seconds + printf("Starting countdown for game start\n"); + } + } else if (gRoomState.state == ROOM_STATE_COUNTING_DOWN) { + if (now >= gRoomState.countdownEndTime) { + gRoomState.state = ROOM_STATE_RUNNING; + // Respawn and heal all players + for (int i = 0; i < MAX_PLAYERS; i++) { + if (players[i].inUse) { + players[i].alive = 1; + players[i].hp = 100; + player_ode_create(&players[i], i); // Recreate body + } + } + printf("Game started!\n"); + } + } else if (gRoomState.state == ROOM_STATE_RUNNING) { + // Check win condition + int aliveCount = 0; + int lastAlive = -1; + for (int i = 0; i < MAX_PLAYERS; i++) { + if (players[i].inUse && players[i].alive) { + aliveCount++; + lastAlive = i; + } + } + if (aliveCount <= 1) { + gRoomState.state = ROOM_STATE_FINISHED; + gRoomState.winnerId = lastAlive; + printf("Game finished! Winner: %s\n", + lastAlive >= 0 ? players[lastAlive].username : "None"); + } + } else if (gRoomState.state == ROOM_STATE_FINISHED) { + // Wait a bit, then reset + static double finishTime = 0.0; + if (finishTime == 0.0) + finishTime = now; + if (now - finishTime > 5.0) { // 5 seconds after finish + gRoomState.state = ROOM_STATE_WAITING; + gRoomState.winnerId = -1; + finishTime = 0.0; + // Remove dead players or something? For now, keep them + printf("Room resetting to waiting\n"); + } + } + } + double t = now_seconds(); if (t >= nextTick) { nextTick += DT; @@ -923,6 +1060,27 @@ int main(void) { } broadcast(sock, players, &im, (int)sizeof(im)); } + + // Send room state every few ticks + static uint32_t roomStateTickDiv = 0; + roomStateTickDiv++; + if (roomStateTickDiv >= 30) { // Every 30 ticks, about 0.5s + roomStateTickDiv = 0; + MsgRoomState rs = {0}; + rs.type = MSG_ROOM_STATE; + rs.state = (uint8_t)gRoomState.state; + rs.countdownRemaining = + (gRoomState.state == ROOM_STATE_COUNTING_DOWN) + ? (float)(gRoomState.countdownEndTime - now_seconds()) + : 0.0f; + rs.winnerId = + (gRoomState.winnerId >= 0) ? (uint8_t)gRoomState.winnerId : 255; + if (gRoomState.winnerId >= 0) { + strncpy(rs.winnerName, players[gRoomState.winnerId].username, + USERNAME_MAX - 1); + } + broadcast(sock, players, &rs, (int)sizeof(rs)); + } } double now = now_seconds();