mapcreator git · master
SDL3 2.5D game and engine using assets, with map editor
C++ 99.3%git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gzsrc/building/craft.cpp raw
#include "building/craft.hpp"
#include "defaults/ui.hpp"
#include "defaults/icons.hpp"
#include "game/game.hpp"
namespace Craft {
const int MENU_BG_COLOR_R = 0;
const int MENU_BG_COLOR_G = 0;
const int MENU_BG_COLOR_B = 0;
const int MENU_BG_COLOR_A = 182;
const int MENU_PADDING = 16;
const float MENU_INNER_W = 800;
const float MENU_INNER_H = 600;
const float MENU_W = MENU_PADDING * 2 + MENU_INNER_W;
const float MENU_H = MENU_PADDING * 2 + MENU_INNER_H;
const int MENU_ITEM_SPACING = 6;
const float MENU_TILE_SIZE = 48.0f;
const float MENU_INFO_W = 300.0f;
const float MENU_BORDER_OUTER = 4.0f;
const float MENU_BORDER_SEPARATOR = 4.0f;
const float MENU_TILE_BORDER = 2.0f;
const int MENU_COLS = 6;
const int MENU_ROWS = 8;
SDL_FRect MENU_CRAFT_BUTTON = {0,0,0,0};
SDL_FRect MENU_INFO_PANEL = {0,0,0,0};
SDL_Color MENU_HOVER_BORDER_C = Default::menu_hovering_color;
ItemCrafting item;
void
draw_ItemInfoPanel(SDL_Renderer* renderer,
TTF_Font* font,
const SDL_FRect& panel_rect,
ItemType t) {
const float border = 4.f;
SDL_SetRenderDrawColor(renderer, 60, 60, 70, 255);
SDL_FRect panel_border{
panel_rect.x - border,
panel_rect.y - border,
panel_rect.w + border * 2.f,
panel_rect.h + border * 2.f
};
SDL_RenderFillRect(renderer, &panel_border);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderFillRect(renderer, &panel_rect);
if (t == ItemType::NONE) return;
const float line_h = 20.f;
const float spacing = 4.f;
float y = panel_rect.y + 6.f;
float x = panel_rect.x + 6.f;
auto draw_line = [&](const std::string& s) {
SDL_Color white{255,255,255,255};
SDL_Surface* surf = TTF_RenderText_Solid(font, s.c_str(), s.length(), white);
if (!surf) return;
SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf);
if (tex) {
SDL_FRect dst{ x, y, (float)surf->w, (float)surf->h };
SDL_RenderTexture(renderer, tex, nullptr, &dst);
SDL_DestroyTexture(tex);
}
y += line_h + spacing;
SDL_DestroySurface(surf);
};
const ItemStats& s = Item::get(t);
draw_line("ITEM:");
draw_line(s.title);
y += spacing;
draw_line("COST:");
for (auto& c : s.cost) {
std::string n;
switch (c.type) {
case ResourceType::WOOD: n = "Wood"; break;
case ResourceType::STONE: n = "Stone"; break;
case ResourceType::CLAY: n = "Clay"; break;
case ResourceType::BONE: n = "Bone"; break;
default: n = "?"; break;
}
draw_line(n + ": " + std::to_string(c.amount));
}
y += spacing;
draw_line("STATS:");
if (s.base_damage > 0) draw_line("Damage: " + std::to_string(s.base_damage));
if (s.base_armor > 0) draw_line("Armor: " + std::to_string(s.base_armor));
draw_line("Health: " + std::to_string(s.base_health));
draw_line("Max Lvl: " + std::to_string(s.max_level));
}
void
draw_CraftMenu(Game* game, BuildingType type, bool hovering_craft_button) {
SDL_Renderer* renderer = game->renderer;
SDL_Rect win_size = game->win_size;
BuildingData_s building_s = BuildingData::building_data[static_cast<size_t>(type)];
const float menu_x = static_cast<float>(win_size.w/2) - MENU_W/2;
const float menu_y = static_cast<float>(win_size.h/2) - MENU_H/2;
const float inner_x = menu_x + MENU_BORDER_OUTER;
const float inner_y = menu_y + MENU_BORDER_OUTER;
const float inner_w = MENU_W - MENU_BORDER_OUTER * 2;
const float inner_h = MENU_H - MENU_BORDER_OUTER * 2;
const float info_x = inner_x + inner_w - MENU_INFO_W;
const float sep_x = info_x - MENU_BORDER_SEPARATOR;
const float grid_x = inner_x;
const float grid_y = inner_y;
const float grid_w = sep_x - inner_x;
const float grid_h = inner_h;
// MENU BACKGROUND
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer,
MENU_BG_COLOR_R, MENU_BG_COLOR_G,
MENU_BG_COLOR_B, MENU_BG_COLOR_A
);
SDL_FRect bg = { menu_x, menu_y, MENU_W, MENU_H };
SDL_RenderFillRect(renderer, &bg);
// LEFT RIGHT SEPARATOR
SDL_FRect separator_bar = { sep_x, inner_y, MENU_BORDER_SEPARATOR, inner_h };
SDL_SetRenderDrawColor(renderer, 80, 80, 80, 255);
SDL_RenderFillRect(renderer, &separator_bar);
// HEADER BAR
const float header_h = 40.0f;
SDL_FRect header_rect = { grid_x, grid_y, grid_w, header_h };
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
SDL_RenderFillRect(renderer, &header_rect);
const std::string header_text =
building_s.title +
std::string(" | Level ") +
std::to_string(BuildingData::get_WorkbenchLevel(building_s.type));
int text_w = 0;
int text_h = 0;
TTF_GetStringSize(Ui::font_menu, header_text.c_str(), header_text.size(), &text_w, &text_h);
float text_x = header_rect.x + (header_rect.w - text_w) * 0.5f;
float text_y = header_rect.y + (header_h - text_h) * 0.5f;
SDL_FRect text_dest = { text_x, text_y, static_cast<float>(text_w), static_cast<float>(text_h) };
SDL_Color text_color = { 230, 230, 230, 255 };
SDL_Surface* surface_text = TTF_RenderText_Blended(Ui::font_menu, header_text.c_str(), header_text.size(), text_color);
if (!surface_text) {
SDL_DestroySurface(surface_text);
return;
}
SDL_Texture* texture_text = SDL_CreateTextureFromSurface(renderer, surface_text);
if (!texture_text) {
SDL_DestroySurface(surface_text);
return;
}
SDL_RenderTexture(renderer, texture_text, nullptr, &text_dest);
SDL_DestroyTexture(texture_text);
// GRID
const float tile_total = MENU_TILE_SIZE + MENU_TILE_BORDER * 2;
const float grid_required_w = MENU_COLS * tile_total + (MENU_COLS - 1) * MENU_ITEM_SPACING;
const float grid_required_h = MENU_ROWS * tile_total + (MENU_ROWS - 1) * MENU_ITEM_SPACING;
const float grid_content_y = grid_y + header_h;
const float grid_start_x = grid_x + (grid_w - grid_required_w) * 0.5f;
const float grid_start_y = grid_content_y + (grid_h - header_h - grid_required_h) * 0.5f;
int active_i_el = -1;
std::vector<ItemType> researched_items =
Item::get_ResearchedItems(game->state_playing->player->researched_items);
size_t i_count = researched_items.size();
size_t index = 0;
for (int r = 0; r < MENU_ROWS; ++r) {
for (int c = 0; c < MENU_COLS; ++c) {
if (Building::draw_menu_curser_grid_active == r*MENU_COLS+c) {
active_i_el = index;
}
float x = grid_start_x + c * (tile_total + MENU_ITEM_SPACING);
float y = grid_start_y + r * (tile_total + MENU_ITEM_SPACING);
SDL_FRect border_rect{ x, y, tile_total, tile_total };
SDL_FRect tile_rect{
x + MENU_TILE_BORDER,
y + MENU_TILE_BORDER,
MENU_TILE_SIZE,
MENU_TILE_SIZE
};
if (Building::draw_menu_curser_grid_active == static_cast<int>(index))
SDL_SetRenderDrawColor(renderer, 20, 215, 0, 255);
else if (Building::draw_menu_curser_grid == static_cast<int>(index))
SDL_SetRenderDrawColor(renderer, MENU_HOVER_BORDER_C.r, MENU_HOVER_BORDER_C.g, MENU_HOVER_BORDER_C.b, MENU_HOVER_BORDER_C.a);
else
SDL_SetRenderDrawColor(renderer, 20, 20, 20, 255);
SDL_RenderFillRect(renderer, &border_rect);
SDL_SetRenderDrawColor(renderer, 60, 60, 60, 255);
SDL_RenderFillRect(renderer, &tile_rect);
if (index < i_count) {
auto it2 = Icon::item_pos.find(researched_items[index]);
if (it2 != Icon::item_pos.end()) {
SDL_FRect src{ it2->second.x * 16.f, it2->second.y * 16.f, 16.f, 16.f };
SDL_RenderTexture(renderer, Icon::icons_texture, &src, &tile_rect);
}
}
index++;
}
}
// INFO PANEL
SDL_FRect info_panel = { info_x, inner_y, MENU_INFO_W, inner_h };
MENU_INFO_PANEL = info_panel;
ItemType item_for_info = ItemType::NONE;
if (active_i_el > -1 && active_i_el < (int)i_count) {
const auto& researched = Item::get_ResearchedItems(game->state_playing->player->researched_items);
item_for_info = researched[static_cast<size_t>(active_i_el)];
}
draw_ItemInfoPanel(renderer, Ui::font_menu, info_panel, item_for_info);
// CRAFT BUTTON
float btn_h = 36.0f;
float btn_w = MENU_INFO_W - MENU_BORDER_OUTER * 2;
float btn_x = info_x + MENU_BORDER_OUTER;
float btn_y = inner_y + inner_h - btn_h - MENU_BORDER_OUTER;
SDL_FRect btn_rect = { btn_x, btn_y, btn_w, btn_h };
SDL_FRect btn_rect_bg = { btn_x-2, btn_y-2, btn_w+4, btn_h+4 };
MENU_CRAFT_BUTTON = btn_rect;
if (hovering_craft_button)
SDL_SetRenderDrawColor(renderer, MENU_HOVER_BORDER_C.r, MENU_HOVER_BORDER_C.g, MENU_HOVER_BORDER_C.b, MENU_HOVER_BORDER_C.a);
else
SDL_SetRenderDrawColor(renderer, 0,0,0, 255);
SDL_RenderFillRect(renderer, &btn_rect_bg);
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
SDL_RenderFillRect(renderer, &btn_rect);
// Draw progress
if (Craft::item.is_crafting) {
float progress = Craft::item.duration / Craft::item.duration_max;
SDL_FRect progress_rect = { btn_x, btn_y, btn_w * progress, btn_h };
SDL_SetRenderDrawColor(renderer, 100, 200, 100, 255);
SDL_RenderFillRect(renderer, &progress_rect);
}
// Button label
const std::string btn_text = "Craft";
int r_w = 0;
int r_h = 0;
TTF_GetStringSize(Ui::font_menu, btn_text.c_str(), btn_text.size(), &r_w, &r_h);
float r_x = btn_x + (btn_w - r_w) * 0.5f;
float r_y = btn_y + (btn_h - r_h) * 0.5f;
SDL_FRect r_dest = { r_x, r_y, static_cast<float>(r_w), static_cast<float>(r_h) };
SDL_Color r_color = { 230, 230, 230, 255 };
SDL_Surface* r_surface = TTF_RenderText_Blended(Ui::font_menu, btn_text.c_str(), btn_text.size(), r_color);
if (!r_surface) {
SDL_DestroySurface(r_surface);
return;
}
SDL_Texture* r_texture = SDL_CreateTextureFromSurface(renderer, r_surface);
if (!r_texture) {
SDL_DestroySurface(r_surface);
return;
}
SDL_RenderTexture(renderer, r_texture, nullptr, &r_dest);
SDL_DestroyTexture(r_texture);
}
bool
is_CursorOverMenuInfoPanel(const SDL_FPoint mouse_pos) {
std::cout << "IP " << MENU_INFO_PANEL.x << " " << MENU_INFO_PANEL.y << " " << MENU_INFO_PANEL.w << " " << MENU_INFO_PANEL.h << " MPP " << mouse_pos.x << " " << mouse_pos.y << std::endl;
return (
mouse_pos.x >= MENU_INFO_PANEL.x &&
mouse_pos.x <= MENU_INFO_PANEL.x + MENU_INFO_PANEL.w &&
mouse_pos.y >= MENU_INFO_PANEL.y &&
mouse_pos.y <= MENU_INFO_PANEL.y + MENU_INFO_PANEL.h
);
}
bool
cursor_OverCraftButton(const SDL_FPoint mouse_pos) {
return (
mouse_pos.x >= MENU_CRAFT_BUTTON.x &&
mouse_pos.x <= MENU_CRAFT_BUTTON.x + MENU_CRAFT_BUTTON.w &&
mouse_pos.y >= MENU_CRAFT_BUTTON.y &&
mouse_pos.y <= MENU_CRAFT_BUTTON.y + MENU_CRAFT_BUTTON.h
);
}
int
cursor_CraftGridTileIndex(SDL_FPoint mouse, SDL_Rect win_size) {
const float MENU_W = MENU_PADDING * 2 + MENU_INNER_W;
const float MENU_H = MENU_PADDING * 2 + MENU_INNER_H;
const float menu_x = static_cast<float>(win_size.w / 2) - MENU_W / 2;
const float menu_y = static_cast<float>(win_size.h / 2) - MENU_H / 2;
const float inner_x = menu_x + MENU_BORDER_OUTER;
const float inner_y = menu_y + MENU_BORDER_OUTER;
const float inner_w = MENU_W - MENU_BORDER_OUTER * 2;
const float inner_h = MENU_H - MENU_BORDER_OUTER * 2;
const float info_x = inner_x + inner_w - MENU_INFO_W;
const float sep_x = info_x - MENU_BORDER_SEPARATOR;
const float grid_x = inner_x;
const float grid_y = inner_y;
const float grid_w = sep_x - inner_x;
const float grid_h = inner_h;
const float header_h = 40.0f;
const float tile_total = MENU_TILE_SIZE + MENU_TILE_BORDER * 2;
const float grid_required_w = MENU_COLS * tile_total + (MENU_COLS - 1) * MENU_ITEM_SPACING;
const float grid_required_h = MENU_ROWS * tile_total + (MENU_ROWS - 1) * MENU_ITEM_SPACING;
const float grid_content_y = grid_y + header_h;
const float grid_start_x = grid_x + (grid_w - grid_required_w) * 0.5f;
const float grid_start_y = grid_content_y + (grid_h - header_h - grid_required_h) * 0.5f;
if (mouse.x < grid_start_x ||
mouse.y < grid_start_y ||
mouse.x > grid_start_x + grid_required_w ||
mouse.y > grid_start_y + grid_required_h) {
return -1;
}
float rel_x = mouse.x - grid_start_x;
float rel_y = mouse.y - grid_start_y;
const float step = tile_total + MENU_ITEM_SPACING;
int c = static_cast<int>(rel_x / step);
int r = static_cast<int>(rel_y / step);
if (c < 0 || c >= MENU_COLS || r < 0 || r >= MENU_ROWS) {
return -1;
}
float cx = rel_x - c * step;
float cy = rel_y - r * step;
if (cx < MENU_TILE_BORDER || cx > MENU_TILE_BORDER + MENU_TILE_SIZE ||
cy < MENU_TILE_BORDER || cy > MENU_TILE_BORDER + MENU_TILE_SIZE) {
return -1;
}
return r * MENU_COLS + c;
}
bool
craft_Start(Inventory* inventory, ItemType type) {
std::cout << "CRAFTING START " << (int)type << std::endl;
Item::craft_ItemStart(inventory, type, Craft::item);
return true;
}
void
craft_Stop() {
Item::craft_Stop(Craft::item);
}
bool
craft_Continue(Inventory* inventory, Messages* messages) {
return Item::craft_Item(inventory, Craft::item, messages);
}
}