forked from NotAShelf/rogged
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ie3b66d17f6f660c9b9a719210bd86f9f6a6a6964
202 lines
5.9 KiB
C
202 lines
5.9 KiB
C
#include "render.h"
|
|
#include "common.h"
|
|
#include "raylib.h"
|
|
#include "settings.h"
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
|
|
void render_map(Map *map) {
|
|
for (int y = 0; y < MAP_HEIGHT; y++) {
|
|
for (int x = 0; x < MAP_WIDTH; x++) {
|
|
Rectangle rect = {(float)(x * TILE_SIZE), (float)(y * TILE_SIZE),
|
|
(float)TILE_SIZE, (float)TILE_SIZE};
|
|
|
|
switch (map->tiles[y][x]) {
|
|
case TILE_WALL:
|
|
DrawRectangleRec(rect, DARKGRAY);
|
|
break;
|
|
case TILE_FLOOR:
|
|
DrawRectangleRec(rect, BLACK);
|
|
break;
|
|
case TILE_STAIRS:
|
|
DrawRectangleRec(rect, (Color){100, 100, 100, 255});
|
|
// Draw stairs marker
|
|
DrawText(">", x * TILE_SIZE + 4, y * TILE_SIZE + 2, 12, WHITE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void render_player(Player *p) {
|
|
Rectangle rect = {(float)(p->x * TILE_SIZE), (float)(p->y * TILE_SIZE),
|
|
(float)TILE_SIZE, (float)TILE_SIZE};
|
|
DrawRectangleRec(rect, BLUE);
|
|
}
|
|
|
|
void render_enemies(Enemy *enemies, int count) {
|
|
for (int i = 0; i < count; i++) {
|
|
if (!enemies[i].alive)
|
|
continue;
|
|
|
|
Rectangle rect = {(float)(enemies[i].x * TILE_SIZE),
|
|
(float)(enemies[i].y * TILE_SIZE), (float)TILE_SIZE,
|
|
(float)TILE_SIZE};
|
|
|
|
// Different colors based on enemy type
|
|
Color enemy_color;
|
|
switch (enemies[i].type) {
|
|
case ENEMY_GOBLIN:
|
|
enemy_color = (Color){150, 50, 50, 255}; // dark red
|
|
break;
|
|
case ENEMY_SKELETON:
|
|
enemy_color = (Color){200, 200, 200, 255}; // light gray
|
|
break;
|
|
case ENEMY_ORC:
|
|
enemy_color = (Color){50, 150, 50, 255}; // dark green
|
|
break;
|
|
default:
|
|
enemy_color = RED;
|
|
break;
|
|
}
|
|
|
|
DrawRectangleRec(rect, enemy_color);
|
|
|
|
// Draw hp bar above enemy
|
|
int hp_percent =
|
|
(enemies[i].hp * TILE_SIZE) / 10; // FIXME: assuming max 10 hp, for now
|
|
if (hp_percent > 0) {
|
|
Rectangle hp_bar = {(float)(enemies[i].x * TILE_SIZE),
|
|
(float)(enemies[i].y * TILE_SIZE - 4),
|
|
(float)hp_percent, 3};
|
|
DrawRectangleRec(hp_bar, GREEN);
|
|
}
|
|
}
|
|
}
|
|
|
|
void render_items(Item *items, int count) {
|
|
for (int i = 0; i < count; i++) {
|
|
if (items[i].picked_up)
|
|
continue;
|
|
|
|
Rectangle rect = {(float)(items[i].x * TILE_SIZE),
|
|
(float)(items[i].y * TILE_SIZE), (float)TILE_SIZE,
|
|
(float)TILE_SIZE};
|
|
|
|
// Different colors based on item type
|
|
Color item_color;
|
|
switch (items[i].type) {
|
|
case ITEM_POTION:
|
|
item_color = (Color){255, 100, 100, 255}; // red/pink
|
|
break;
|
|
case ITEM_WEAPON:
|
|
item_color = (Color){255, 255, 100, 255}; // yellow
|
|
break;
|
|
case ITEM_ARMOR:
|
|
item_color = (Color){100, 100, 255, 255}; // blue
|
|
break;
|
|
default:
|
|
item_color = GREEN;
|
|
break;
|
|
}
|
|
|
|
DrawRectangleRec(rect, item_color);
|
|
}
|
|
}
|
|
|
|
void render_ui(Player *p) {
|
|
// UI background bar at bottom of screen
|
|
Rectangle ui_bg = {0, (float)(MAP_HEIGHT * TILE_SIZE), (float)SCREEN_WIDTH,
|
|
60};
|
|
DrawRectangleRec(ui_bg, (Color){30, 30, 30, 255});
|
|
|
|
// Draw dividing line
|
|
DrawLine(0, MAP_HEIGHT * TILE_SIZE, SCREEN_WIDTH, MAP_HEIGHT * TILE_SIZE,
|
|
GRAY);
|
|
|
|
// Player hp
|
|
char hp_text[32];
|
|
snprintf(hp_text, sizeof(hp_text), "HP: %d/%d", p->hp, p->max_hp);
|
|
DrawText(hp_text, 10, MAP_HEIGHT * TILE_SIZE + 10, 20, RED);
|
|
|
|
// Player attack
|
|
char atk_text[32];
|
|
snprintf(atk_text, sizeof(atk_text), "ATK: %d", p->attack);
|
|
DrawText(atk_text, 150, MAP_HEIGHT * TILE_SIZE + 10, 20, YELLOW);
|
|
|
|
// Floor number
|
|
char floor_text[32];
|
|
snprintf(floor_text, sizeof(floor_text), "Floor: %d", p->floor);
|
|
DrawText(floor_text, 280, MAP_HEIGHT * TILE_SIZE + 10, 20, WHITE);
|
|
|
|
// Defense stat
|
|
char def_text[32];
|
|
snprintf(def_text, sizeof(def_text), "DEF: %d", p->defense);
|
|
DrawText(def_text, 420, MAP_HEIGHT * TILE_SIZE + 10, 20, BLUE);
|
|
|
|
// Inventory count
|
|
char inv_text[32];
|
|
snprintf(inv_text, sizeof(inv_text), "Inv: %d/%d", p->inventory_count,
|
|
MAX_INVENTORY);
|
|
DrawText(inv_text, 530, MAP_HEIGHT * TILE_SIZE + 10, 16, GREEN);
|
|
|
|
// Show first item in inventory if any
|
|
if (p->inventory_count > 0 && !p->inventory[0].picked_up) {
|
|
const char *item_name = "";
|
|
switch (p->inventory[0].type) {
|
|
case ITEM_POTION:
|
|
item_name = "Potion";
|
|
break;
|
|
case ITEM_WEAPON:
|
|
item_name = "Weapon";
|
|
break;
|
|
case ITEM_ARMOR:
|
|
item_name = "Armor";
|
|
break;
|
|
default:
|
|
item_name = "?";
|
|
break;
|
|
}
|
|
char first_item[48];
|
|
snprintf(first_item, sizeof(first_item), "[%s +%d]", item_name,
|
|
p->inventory[0].power);
|
|
DrawText(first_item, 10, MAP_HEIGHT * TILE_SIZE + 35, 14, LIGHTGRAY);
|
|
}
|
|
|
|
// Controls hint
|
|
DrawText("WASD: Move | U: Use Item | Q: Quit", 280,
|
|
MAP_HEIGHT * TILE_SIZE + 35, 14, GRAY);
|
|
}
|
|
|
|
void render_game_over(void) {
|
|
// Semi-transparent overlay
|
|
Rectangle overlay = {0, 0, (float)SCREEN_WIDTH, (float)SCREEN_HEIGHT};
|
|
DrawRectangleRec(overlay, (Color){0, 0, 0, 200});
|
|
|
|
// Game over text
|
|
const char *title = "GAME OVER";
|
|
int title_width = MeasureText(title, 60);
|
|
DrawText(title, (SCREEN_WIDTH - title_width) / 2, SCREEN_HEIGHT / 2 - 30, 60,
|
|
RED);
|
|
|
|
const char *subtitle = "Press R to restart or Q to quit";
|
|
int sub_width = MeasureText(subtitle, 20);
|
|
DrawText(subtitle, (SCREEN_WIDTH - sub_width) / 2, SCREEN_HEIGHT / 2 + 40, 20,
|
|
WHITE);
|
|
}
|
|
|
|
void render_message(const char *message) {
|
|
if (message == NULL)
|
|
return;
|
|
|
|
// Draw message box
|
|
Rectangle msg_bg = {(float)(SCREEN_WIDTH / 2 - 150),
|
|
(float)(SCREEN_HEIGHT / 2 - 30), 300, 60};
|
|
DrawRectangleRec(msg_bg, (Color){50, 50, 50, 230});
|
|
DrawRectangleLines((int)msg_bg.x, (int)msg_bg.y, (int)msg_bg.width,
|
|
(int)msg_bg.height, WHITE);
|
|
|
|
int msg_width = MeasureText(message, 20);
|
|
DrawText(message, (SCREEN_WIDTH - msg_width) / 2, SCREEN_HEIGHT / 2 - 10, 20,
|
|
WHITE);
|
|
}
|