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/character/message.cpp raw
#include "character/message.hpp"
#include <iostream>
#include "defaults/ui.hpp"
#include "map/map.hpp"
#include "game/game.hpp"
#include "inventory/inventory.hpp"
#define TOP_RIGHT_ICON_BG 180, 180, 180
Messages::Messages() {
messages.clear();
messages_data = {
{MessageKey::MOIN, {10, MessageType::CHARACTER, "I should collect some things.."}},
{MessageKey::BUILDING_TOOL_REQUIRED, {5, MessageType::CHARACTER, "I need a building tool!"}},
{MessageKey::PLAYER_EXHAUSTED, {5, MessageType::CHARACTER, "I am exhausted..."}},
{MessageKey::DISCOVERED_RESOURCE, {5, MessageType::CHARACTER, "A new resource!"}},
{MessageKey::DISCOVERED_VEGETABLE, {5, MessageType::CHARACTER, "A new vegetable!"}},
{MessageKey::DISCOVERED_BUILDING, {5, MessageType::CHARACTER, "Maybe i can build something with it.."}},
{MessageKey::THIRST_20, {10, MessageType::CHARACTER, "I should drink something.."}},
{MessageKey::THIRST_0, {10, MessageType::CHARACTER, "No water no life.."}},
{MessageKey::WATER_APPRECIATION, {5, MessageType::CHARACTER, "Hmmm water"}},
{MessageKey::EAT_APPRECIATION, {5, MessageType::CHARACTER, "Omnjomnjom"}},
{MessageKey::CRAFTED_ITEM, {10, MessageType::CHARACTER, "Whatever i can do with that.."}},
{MessageKey::ADD_INVENTORY, {10, MessageType::INVENTORY, "Added item: "}},
{MessageKey::ADD_RESOURCE, {10, MessageType::RESOURCE, "Resource "}},
{MessageKey::ADD_VEGETABLE, {10, MessageType::VEGETABLE, "Vegetable "}},
{MessageKey::ADD_VEGETABLE_SEED, {10, MessageType::VEGETABLE_SEED, "Seed "}},
{MessageKey::NOTHING_TO_INTERACT, {4, MessageType::CHARACTER, "I cant find anything to interact with.."}},
};
}
void Messages::Add(MessageKey key, void* type_data) {
auto base = messages_data.find(key);
if (base == messages_data.end())
return;
Message_s msg = base->second;
msg.type_data = type_data;
if (msg.message_type == MessageType::INVENTORY) {
size_t* id_ptr = static_cast<size_t*>(msg.type_data);
std::cout << "ADD ID: " << *id_ptr << std::endl;
messages.emplace(key, msg);
return;
}
if (msg.message_type == MessageType::RESOURCE) {
ResourceType new_type = *static_cast<ResourceType*>(msg.type_data);
auto range = messages.equal_range(key);
for (auto it = range.first; it != range.second; ) {
if (it->second.message_type == MessageType::RESOURCE) {
ResourceType old_type = *static_cast<ResourceType*>(it->second.type_data);
if (old_type == new_type) {
it = messages.erase(it);
continue;
}
}
++it;
}
messages.emplace(key, msg);
return;
}
if (msg.message_type == MessageType::VEGETABLE) {
ResourceType new_type = *static_cast<ResourceType*>(msg.type_data);
auto range = messages.equal_range(key);
for (auto it = range.first; it != range.second; ) {
if (it->second.message_type == MessageType::VEGETABLE) {
ResourceType old_type = *static_cast<ResourceType*>(it->second.type_data);
if (old_type == new_type) {
it = messages.erase(it);
continue;
}
}
++it;
}
messages.emplace(key, msg);
return;
}
auto range = messages.equal_range(key);
for (auto it = range.first; it != range.second; ) {
it = messages.erase(it);
}
messages.emplace(key, msg);
}
void
Messages::Update() {
for (auto it = messages.begin(); it != messages.end(); ) {
Message_s &msg = it->second;
msg.duration -= Default::delta_time;
if (msg.duration <= 0.0f) {
/*
if (msg.message_type == MessageType::VEGETABLE)
delete static_cast<VegetableData::Type*>(msg.type_data);
else
*/
if (msg.message_type == MessageType::RESOURCE)
delete static_cast<ResourceType*>(msg.type_data);
else
if (msg.message_type == MessageType::INVENTORY)
delete static_cast<size_t*>(msg.type_data);
else
if (msg.message_type == MessageType::VEGETABLE)
delete static_cast<ResourceType*>(msg.type_data);
it = messages.erase(it);
continue;
}
++it;
}
}
void
Messages::Render(SDL_Renderer* renderer, float center_x, float start_y) {
if (!messages.empty() && Ui::font_tiny) {
const float row_h = 14.0f;
// Stable iteration order
std::vector<MessageKey> keys;
keys.reserve(messages.size());
for (const auto &kv : messages)
keys.push_back(kv.first);
for (size_t i = 0; i < keys.size(); ) {
MessageKey key = keys[i];
auto it = messages.find(key);
if (it == messages.end()) {
++i;
continue;
}
Message_s &msg = it->second;
if (msg.message_type == MessageType::INVENTORY ||
msg.message_type == MessageType::RESOURCE ||
msg.message_type == MessageType::VEGETABLE) {
++i;
continue;
}
// Render message
SDL_Color col{255, 255, 255, 255};
SDL_Surface* surf =
TTF_RenderText_Blended(Ui::font_message, msg.message.c_str(), msg.message.length(), col);
SDL_Surface* surf_bg =
TTF_RenderText_Blended(Ui::font_message, msg.message.c_str(), msg.message.length(), {126,126,126,164});
if (surf && surf_bg) {
SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf);
SDL_Texture* tex_bg = SDL_CreateTextureFromSurface(renderer, surf_bg);
if (tex && tex_bg) {
SDL_FRect dst{
Scale(center_x + Map::offset.x) - (surf->w * 0.5f),
Scale(start_y + Map::offset.y + 22.0f),
(float)surf->w,
(float)surf->h
};
SDL_FRect dst_bg = dst;
dst_bg.x -= 1;
dst_bg.y -= 1;
SDL_RenderTexture(renderer, tex, nullptr, &dst);
SDL_RenderTexture(renderer, tex_bg, nullptr, &dst_bg);
SDL_DestroyTexture(tex);
SDL_DestroyTexture(tex_bg);
}
SDL_DestroySurface(surf);
SDL_DestroySurface(surf_bg);
}
start_y -= row_h;
++i;
}
}
}
void Messages::render_InventoryMessages(Game* game, Inventory* inventory) {
if (messages.empty() || !Ui::font_menu)
return;
const float bar_padding = 6.0f;
const float bar_height_min = 48.0f;
const float icon_bg_size = 48.0f;
const float right_margin = 10.0f;
const float spacing = 6.0f;
// Collect inventory messages
std::vector<const Message_s*> inv_msgs;
inv_msgs.reserve(messages.size());
for (auto &kv : messages) {
if ( kv.second.message_type == MessageType::INVENTORY ||
kv.second.message_type == MessageType::RESOURCE ||
kv.second.message_type == MessageType::VEGETABLE ||
kv.second.message_type == MessageType::VEGETABLE_SEED)
inv_msgs.push_back(&kv.second);
}
if (inv_msgs.empty())
return;
// Sort by remaining duration
std::sort(inv_msgs.begin(), inv_msgs.end(),
[](const Message_s* a, const Message_s* b){
return a->duration > b->duration;
});
// Measure max text width
float max_text_w = 0.0f;
for (const Message_s* msg : inv_msgs) {
std::string text ;
if (msg->message_type == MessageType::INVENTORY) {
size_t id = *static_cast<size_t*>(msg->type_data);
// std::cout << "IDDD: " << id << " " << inventory->items.size() << " " << inventory->items.front()->id << std::endl;
InventoryItem* item = inventory->get_ItemById(id);
if (!item) continue;
text = "Added item: " + Item::to_String(item->type);
} else
if (msg->message_type == MessageType::RESOURCE) {
ResourceType* rt = static_cast<ResourceType*>(msg->type_data);
ResourceType type = *rt;
int amount = inventory->resources[type];
text = std::to_string(amount);
}
else
if (msg->message_type == MessageType::VEGETABLE) {
VegetableData::Type* vtype = static_cast<VegetableData::Type*>(msg->type_data);
auto it = inventory->vegetables.find(*vtype);
int amount = 0;
if (it != inventory->vegetables.end())
amount = it->second.count;
text = std::to_string(amount);
}
else
if (msg->message_type == MessageType::VEGETABLE_SEED) {
VegetableData::Type* vtype = static_cast<VegetableData::Type*>(msg->type_data);
auto it = inventory->seeds.find(*vtype);
int amount = 0;
if (it != inventory->seeds.end())
amount = it->second.count;
text = std::to_string(amount);
}
SDL_Color col{255,255,255,255};
SDL_Surface* surf = TTF_RenderText_Blended(Ui::font_menu, text.c_str(), text.length(), col);
if (surf) {
max_text_w = std::max(max_text_w, static_cast<float>(surf->w));
SDL_DestroySurface(surf);
}
}
float total_width = max_text_w + bar_padding * 2.0f + icon_bg_size + bar_padding;
float bar_x = (float)game->win_size.w - total_width - right_margin;
float y = 10.0f;
// Render messages
for (const Message_s* msg : inv_msgs) {
InventoryItem* item = nullptr;
ResourceType* rtype = nullptr;
VegetableData::Type* vtype = nullptr;
bool is_seed = false;
std::string text ;
if (msg->message_type == MessageType::INVENTORY) {
size_t id = *static_cast<size_t*>(msg->type_data);
item = inventory->get_ItemById(id);
if (!item) continue;
text = "Added item: " + Item::to_String(item->type);
} else
if (msg->message_type == MessageType::RESOURCE) {
rtype = static_cast<ResourceType*>(msg->type_data);
int amount = inventory->resources[*rtype];
text = std::to_string(amount);
}
else
if (msg->message_type == MessageType::VEGETABLE) {
vtype = static_cast<VegetableData::Type*>(msg->type_data);
auto it = inventory->vegetables.find(*vtype);
int amount = 0;
if (it != inventory->vegetables.end())
amount = it->second.count;
text = std::to_string(amount);
}
else
if (msg->message_type == MessageType::VEGETABLE_SEED) {
is_seed = true;
vtype = static_cast<VegetableData::Type*>(msg->type_data);
auto it = inventory->seeds.find(*vtype);
int amount = 0;
if (it != inventory->seeds.end())
amount = it->second.count;
text = std::to_string(amount);
}
SDL_Color col{255,255,255,255};
SDL_Surface* surf = TTF_RenderText_Blended(Ui::font_menu, text.c_str(), text.length(), col);
if (!surf) continue;
SDL_Texture* tex = SDL_CreateTextureFromSurface(game->renderer, surf);
if (!tex) {
SDL_DestroySurface(surf);
continue;
}
float text_w = surf->w;
float text_h = surf->h;
float bar_h = std::max(text_h + bar_padding * 2.0f, bar_height_min);
SDL_FRect bar_rect{bar_x, y, total_width, bar_h};
// Bar background
SDL_SetRenderDrawBlendMode(game->renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(game->renderer, 30, 30, 30, 170);
SDL_RenderFillRect(game->renderer, &bar_rect);
SDL_SetRenderDrawColor(game->renderer, 90, 90, 90, 210);
SDL_RenderRect(game->renderer, &bar_rect);
// Text
SDL_FRect dst_text{
bar_x + bar_padding,
y + bar_padding + bar_height_min/2 - (text_h*0.75f),
text_w,
text_h
};
SDL_RenderTexture(game->renderer, tex, nullptr, &dst_text);
SDL_DestroyTexture(tex);
SDL_DestroySurface(surf);
// Icon
// Determine which payload we have
// Now select the correct icon source
bool draw_icon = false;
SDL_FRect src;
// ---- INVENTORY ITEM ----
if (item && item->type != ItemType::NONE) {
auto it = Icon::item_pos.find(item->type);
if (it != Icon::item_pos.end()) {
src = SDL_FRect{
it->second.x * 16.0f,
it->second.y * 16.0f,
16.0f,
16.0f
};
draw_icon = true;
}
}
// ---- RESOURCE ----
if (rtype && *rtype != ResourceType::NONE) {
auto it = Icon::resource_pos.find(*rtype);
if (it != Icon::resource_pos.end()) {
src = SDL_FRect{
it->second.x * 16.0f,
it->second.y * 16.0f,
16.0f,
16.0f
};
draw_icon = true;
}
}
// ---- VEGETABLE ----
if (vtype && *vtype != VegetableData::Type::NONE) {
SDL_Point pos = VegetableData::get_IconTilePosByType(*vtype, is_seed);
src = SDL_FRect{
pos.x * 16.0f,
pos.y * 16.0f,
16.0f,
16.0f
};
draw_icon = true;
}
// ---- DRAW IF AVAILABLE ----
if (draw_icon) {
SDL_FRect icon_bg{
bar_x + total_width - icon_bg_size - bar_padding,
y + (bar_h - icon_bg_size) * 0.5f,
icon_bg_size,
icon_bg_size
};
SDL_SetRenderDrawColor(game->renderer, TOP_RIGHT_ICON_BG, 180);
SDL_RenderFillRect(game->renderer, &icon_bg);
SDL_SetRenderDrawColor(game->renderer, 0, 0, 0, 255);
SDL_RenderRect(game->renderer, &icon_bg);
SDL_FRect dst{
icon_bg.x,
icon_bg.y,
icon_bg_size,
icon_bg_size
};
SDL_RenderTexture(game->renderer, Icon::icons_texture, &src, &dst);
}
y += bar_h + spacing;
}
}