Brandling Safari: LAN safari-zone creature catching on the HD-2D engine

- Authoritative 30 Hz server (ENet, SQLite): accounts, characters, wild AI, tall grass /
  water / wandering spawns, fishing, captures, follower chains, clock + weather, LAN beacon
- Client: title / join / character creator / play screens, prediction + reconciliation,
  interpolated players and parties, HD-2D UI (dialogue with Professor Henry, HUD, collection)
- Shared deterministic zone generator, movement, protocol, roster, appearance
- Paper-doll character art pipeline (PixelLab base walk + per-item animation edits)
- Brandling roster from the company list (logo colors, jev types), Blender safari props
- Headless test bot
This commit is contained in:
Gabe
2026-10-02 15:20:27 -05:00
commit 238cd9c6c3
3409 changed files with 100493 additions and 0 deletions

60
client/main.cpp Normal file
View File

@@ -0,0 +1,60 @@
// Brandling Safari client.
//
// safari_client title screen (Host & Play / Join a LAN game)
// safari_client --host start a local server and join it
// safari_client --connect 192.168.1.20 join a server directly
//
// Headless captures (hidden window, nothing pops up, input ignored):
// safari_client --screenshot out.png --frames 240 --connect 127.0.0.1 --auto-create --profile bot1
// [--move x,y] [--run] [--yaw deg] [--dist d] [--key 120:space] [--screen creator]
// [--look female,2,hair_long,hat_cap,top_hoodie,bottom_pants,shoes_boots] [--hour 18] [--weather rain]
#include "App.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
namespace {
bool pair(const char* s, float& a, float& b) { return std::sscanf(s, "%f,%f", &a, &b) == 2; }
} // namespace
int main(int argc, char** argv) {
bs::Options o;
for (int i = 1; i < argc; ++i) {
auto is = [&](const char* f) { return std::strcmp(argv[i], f) == 0; };
auto next = [&]() -> const char* { return i + 1 < argc ? argv[++i] : ""; };
if (is("--screenshot")) o.screenshot = next();
else if (is("--frames")) o.frames = std::atoi(next());
else if (is("--size")) std::sscanf(next(), "%dx%d", &o.width, &o.height);
else if (is("--show")) o.show = true;
else if (is("--connect")) o.connect = next();
else if (is("--host")) o.host = true;
else if (is("--port")) o.port = uint16_t(std::atoi(next()));
else if (is("--auto-create")) o.autoCreate = true;
else if (is("--auto-dialogue")) o.autoDialogue = true;
else if (is("--screen")) o.screen = next();
else if (is("--profile")) o.profile = next();
else if (is("--name")) o.name = next();
else if (is("--move")) pair(next(), o.move.x, o.move.y);
else if (is("--run")) o.run = true;
else if (is("--yaw")) o.yaw = float(std::atof(next())), o.hasYaw = true;
else if (is("--dist")) o.dist = float(std::atof(next()));
else if (is("--hour")) o.hour = float(std::atof(next()));
else if (is("--weather")) o.weather = next();
else if (is("--key")) o.keys.push_back(next());
else if (is("--look")) o.look = next();
else if (is("--help") || is("-h")) {
std::puts("safari_client [--host | --connect host[:port]] [--port N] [--profile name]\n"
" captures: --screenshot out.png [--frames N] [--size WxH] [--show] [--auto-create] [--name N]\n"
" [--move x,y] [--run] [--yaw deg] [--dist d] [--key frame:space|e|f|tab|enter]\n"
" [--screen title|creator] [--look body,skin,hair,hat,top,bottom,shoes[,colors...]]\n"
" [--hour H] [--weather clear|cloudy|rain|storm|fog]");
return 0;
}
}
bs::App app(o);
return app.run();
}