1#define RLIGHTS_IMPLEMENTATION
25 SetTraceLogLevel(LOG_WARNING);
26 SetConfigFlags(FLAG_WINDOW_RESIZABLE);
27 InitWindow(800, 600,
"Zappy");
31 TraceLog(LOG_WARNING,
"Failed to load font %s, using default",
FONT_PATH.data());
48 SetTraceLogLevel(LOG_ERROR);
50 SetTraceLogLevel(LOG_WARNING);
52 throw std::runtime_error(
"Failed to load player model: " + std::string(
PLAYER_MODEL_PATH));
53 for (
int i = 0; i <
_playerModel.materialCount && i < 6; i++)
56 SetTraceLogLevel(LOG_ERROR);
58 SetTraceLogLevel(LOG_WARNING);
60 throw std::runtime_error(
"Failed to load egg model: " + std::string(
EGG_MODEL_PATH));
62 _eggModel.materials[0].maps[MATERIAL_MAP_DIFFUSE].color = {235, 235, 235, 255};
63 for (
int i = 0; i <
_eggModel.materialCount && i < 2; i++)
66 SetTraceLogLevel(LOG_ERROR);
68 SetTraceLogLevel(LOG_WARNING);
70 throw std::runtime_error(
"Failed to load food model: " + std::string(
FOOD_MODEL_PATH));
72 SetTraceLogLevel(LOG_ERROR);
74 SetTraceLogLevel(LOG_WARNING);
76 throw std::runtime_error(
"Failed to load crystal model: " +
80 LoadShader(
"gui/assets/shaders/lighting.vs",
"gui/assets/shaders/lighting.fs");
83 for (
int i = 0; i <
_foodModel.materialCount; i++)
88 _sun = CreateLight(LIGHT_DIRECTIONAL, {0.0f, 1000.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, WHITE,
92 float ambient[4] = {1.0f, 1.0f, 1.0f, 1.0f};
104 float scaledDelta = GetFrameTime();
115 ClearBackground(BLACK);
136 if (IsKeyPressed(KEY_F)) {
169 int sh = GetScreenHeight();
173 Vector2 mouse = GetMousePosition();
184 if (IsKeyPressed(KEY_L)) {
189 if (IsKeyPressed(KEY_F3)) {
216 .
width = GetScreenWidth(),
217 .height = GetScreenHeight(),
218 .position = GetWindowPosition(),
219 .monitor = GetCurrentMonitor(),
220 .fullscreen = IsWindowFullscreen(),
233 player.visual.update(GetFrameTime());
234 Vector3 worldPos = player.visual.pos;
241 player.visual.update(GetFrameTime());
242 Vector3 worldPos = player.visual.pos;
252 egg.visual.update(GetFrameTime());
270 std::array<float, 7> rotations;
273 res, slotIndices, rotations,
289 for (
const auto& line : ab->getLines()) {
290 if (line.alpha <= 0.0f)
continue;
291 Color c = {line.color.r, line.color.g, line.color.b,
292 static_cast<unsigned char>(line.alpha * 255)};
293 DrawLine3D(line.a, line.b, c);
295 for (
const auto& p : ab->getParticles()) {
296 if (!p.active)
continue;
297 Color c = {p.color.r, p.color.g, p.color.b,
static_cast<unsigned char>(p.alpha * 255)};
298 DrawSphere(p.pos, p.size, c);
306 std::sort(group.begin(), group.end(),
307 [](
const Player* a,
const Player* b) { return a->level > b->level; });
311 Vector2 screenPos = GetWorldToScreen(worldPos,
_cam.
camera());
316 .setBackgroundAlpha(160)
322 for (
const Player* p : group)
327 builder.
draw(screenPos);
339 [
this](
const std::string& teamName) {
return _getTeamColor(teamName); });
390 BoundingBox bbox = GetModelBoundingBox(
_eggModel);
428 int screenHeight = GetScreenHeight();
429 float scale = screenHeight / 600.0f;
430 scale = std::max(0.5f, std::min(scale, 2.5f));
431 return static_cast<int>(baseFontSize * scale);
438 Ray ray = GetMouseRay(GetMousePosition(),
_cam.
camera());
452 constexpr float thresh =
TILE_SIZE / 4.0f;
453 constexpr float threshSq = thresh * thresh;
455 std::vector<const Player*> all;
459 std::vector<bool> assigned(all.size(),
false);
460 std::vector<std::vector<const Player*>> groups;
462 for (
size_t i = 0; i < all.size(); i++) {
463 if (assigned[i])
continue;
464 std::vector<const Player*> group = {all[i]};
466 const Vector3& pi = all[i]->visual.pos;
467 for (
size_t j = i + 1; j < all.size(); j++) {
468 if (assigned[j])
continue;
469 const Vector3& pj = all[j]->visual.pos;
470 float dx = pi.x - pj.x;
471 float dz = pi.z - pj.z;
472 bool nearbyVisual = dx * dx + dz * dz < threshSq;
473 bool sameIncant = all[i]->incanting && all[j]->incanting && all[i]->x == all[j]->x &&
474 all[i]->y == all[j]->y;
475 if (nearbyVisual || sameIncant) {
476 group.push_back(all[j]);
480 groups.push_back(std::move(group));
487 if (group.size() > 1) {
488 const Player* ref = group[0];
489 bool allIncantingOnSameTile = ref->incanting;
490 for (
size_t k = 1; allIncantingOnSameTile && k < group.size(); k++)
491 allIncantingOnSameTile =
492 group[k]->incanting && group[k]->x == ref->
x && group[k]->y == ref->
y;
493 if (allIncantingOnSameTile)
497 return group[0]->visual.pos;
503 float bob = sinf(
static_cast<float>(GetTime()) * 4.0f) * 0.08f;
505 float arrowBase = basePos.y + modelTopY + 0.05f + bob;
506 float shaftHeight = 0.18f;
507 float shaftRadius = 0.03f;
508 float headHeight = 0.14f;
509 float headRadius = 0.08f;
512 Vector3 shaftBot = {basePos.x, arrowBase + headHeight, basePos.z};
513 DrawCylinder(shaftBot, shaftRadius, shaftRadius, shaftHeight, 8,
SELECTION_COLOR);
516 Vector3 coneBottom = {basePos.x, arrowBase, basePos.z};
517 DrawCylinder(coneBottom, headRadius, 0.0f, headHeight, 8,
SELECTION_COLOR);
Base class for behaviors that produce visual drawables: sphere particles and line segments....
void init(float worldWidth, float worldHeight)
int followedPlayerId() const
bool isFollowActive() const
bool isFreecamActive() const
void update(float dt, float worldWidth, float worldHeight, const WorldState *world)
void startFollow(int playerId)
const Camera3D & camera() const
static Color getTeamColor(int index)
Returns a unique color for a team based on its index. Will repeat if more teams than palette size.
static void drawEgg(Vector3 &worldPos, Color teamColor, Model &model, float rotation=0.0f, const Color *baseMats=nullptr, float modelSize=0.3f)
Draws an egg at the given world position.
static void drawResources(const Resources &resources, const std::array< int, 7 > &slotIndices, const std::array< float, 7 > &rotations, const Vector3 &tileCenter, float tileSize, Model &foodModel, float foodModelSize, Model &crystalModel, float crystalModelSize, float baseSize=0.15f)
Draws all resources for a tile using precomputed slot indices.
static void drawPlayer(Vector3 &worldPos, Color teamColor, float rotation, Model &model, const Color *baseMats, float modelSize=0.4f)
Draws a player at the given world position.
unsigned int serverUptimeSeconds
int64_t gameDurationTicks
static void drawTiles(int width, int height, float tileSize)
Draws filled tile quads for the entire grid in a checkerboard pattern.
static void drawTileHighlight(int tileX, int tileY, int worldWidth, int worldHeight, float tileSize, Color color, float lineThickness=1.0f)
Draws a highlight outline around a specific tile.
static const char * get(Key key)
static void setLanguage(Language lang)
static Language getLanguage()
void setTeamColorFunc(std::function< Color(const std::string &)> func)
Sets the team color resolution function.
bool isOpen() const
Checks if panel is currently open.
void draw(int scaledFontSize) const override
Draws the panel and player list.
bool handleInput() override
Processes mouse clicks on player rows.
void setWorld(const WorldState *world)
Sets the world state pointer.
std::optional< SelectionFinder::Selection > getPendingSelection()
Gets and clears any pending selection made by the user.
SelectionFinder::Selection _selection
int _getScaledFontSize(int baseFontSize) const
EntityTooltipWidget _entityTooltip
static constexpr std::string_view FOOD_MODEL_PATH
void _updateSelection(float deltaTime)
std::unordered_map< std::string, Color > _teamColors
Color _playerModelBaseMats[6]
std::unique_ptr< IBackground > _background
std::optional< int > _pendingSpeed
void _drawSelectionHighlight()
static constexpr float EGG_MODEL_SIZE
static constexpr std::string_view CRYSTAL_MODEL_PATH
Color _eggModelBaseMats[2]
std::vector< std::vector< const Player * > > _groupPlayersByVisualProximity() const
static constexpr std::string_view FONT_PATH
Vector3 _groupLabelAnchor(const std::vector< const Player * > &group) const
static constexpr float CRYSTAL_MODEL_SIZE
static constexpr float RESOURCE_SPHERE_BASE_SIZE
static constexpr std::string_view PLAYER_MODEL_PATH
static constexpr float PLAYER_MODEL_SIZE
std::optional< int > getPendingSpeedChange() override
bool shouldClose() override
void _drawSelectionArrow(Vector3 basePos, float modelTopY) const
static constexpr Color SELECTION_COLOR
Color _getTeamColor(const std::string &teamName)
void handleInput() override
WindowSnapshot _savedWindow
static constexpr float FOOD_MODEL_SIZE
void _drawBehaviorParticles(const VisualState &visual)
static constexpr std::string_view EGG_MODEL_PATH
static constexpr float TILE_SIZE
void setDevMode(bool dev, int port, const std::string &machine) override
static constexpr float SELECTION_LINE_THICKNESS
static Vector3 tileToWorld(int tileX, int tileY, int worldWidth, int worldHeight, float tileSize)
Converts tile coordinates to world coordinates (centered on tile).
static Selection findFromRay(const Ray &ray, const GameState &state, float tileSize, const Model &playerModel, float playerModelSize, const Model &eggModel, float eggModelSize, const TileSlotMap &slotMap)
Performs raycast and finds closest entity.
static Selection getEmptySelection()
Returns an empty selection (type None).
static constexpr int PANEL_HEIGHT
void draw(int scaledFontSize) const override
Draws the slider panel at the bottom-left of the screen.
std::optional< int > getPendingSpeedChange()
Returns and clears any pending speed change.
void syncFromServer(int serverTimeUnit)
Snaps to the nearest step index matching serverTimeUnit. No-op if already initialized or serverTimeUn...
void reset()
Resets slider state. Call on reconnect so it re-syncs from the new server.
static constexpr int PANEL_WIDTH
bool handleInput() override
Processes mouse input.
static bool loadFont(const std::string &path)
static std::pair< float, float > slotOffset(int slotIndex)
Returns the XZ offset pair {dx, dz} for a slot index (0-7).
float resourceRotation(int tileX, int tileY, int resourceType) const
Returns the stable random Y rotation for a resource slot, or 0 if absent.
void syncEggs(const std::unordered_map< int, Egg > &eggs)
Syncs egg slot assignments against the current egg map. Assigns slots to new eggs,...
std::array< int, 7 > updateResourceSlots(int tileX, int tileY, const Resources &resources)
Updates slot assignments for all resource types on a tile. Assigns a slot when count goes 0→nonzero,...
void clear()
Resets all state. Call on reconnect.
int eggSlot(int eggId) const
Returns the slot index for an egg id, or -1 if unknown.
Visual-only state for an entity, driven by behaviors each frame. Logical state (x,...
std::vector< std::unique_ptr< IBehavior > > behaviors
bool quitRequested() const
Returns true once the Quit button has been clicked (latched — stays true).
void setDuration(int seconds, int64_t ticks)
Sets the win duration (server-authoritative, from gwt).
void draw(int scaledFontSize) const override
Draws the widget.
void setWinner(const std::string &team, Color color)
Sets the winning team name and highlight color.
bool handleInput() override
Handles button input. Always returns true (overlay blocks all input).
Resources & at(int x, int y)
Accesses the resources at a specific tile coordinate (x, y).
std::vector< std::string > teams
std::unordered_map< int, Player > dyingPlayers
std::unordered_map< int, Egg > eggs
std::unordered_map< int, Player > players
void purgeDyingPlayers() const