#include "ui.h" #include "game.h" #include "settings.h" void resizeInteractionChat(InteractionChat* chat, const Settings* settings) { float renderWidth = GetRenderWidth(); float renderHeight = GetRenderHeight(); float height = settings->interactionChatHeight; chat->rect = (Rectangle){ 0.0, renderHeight - height, renderWidth, height }; } void initInteractionChat(InteractionChat* chat, const Settings* settings) { clearInteractionChat(chat); chat->visible = false; chat->entityId = ENTITY_NONE; resizeInteractionChat(chat, settings); } void showInteractionChat(InteractionChat* chat) { chat->visible = true; } void hideInteractionChat(InteractionChat* chat) { chat->visible = false; } void setInteractionChat(InteractionChat* chat, const char* text) { strncpy(chat->text, text, INTERACTION_CHAT_MAX - 1); chat->textSize = getStringLength(text, INTERACTION_CHAT_MAX); chat->displayUpTo = 0; chat->lastCharacterUpdate = GetTime(); } void writeToInteractionChat(InteractionChat* chat, const char* text) { strncat(chat->text, text, INTERACTION_CHAT_MAX - 1); chat->textSize += getStringLength(text, INTERACTION_CHAT_MAX); chat->textSize %= INTERACTION_CHAT_MAX; chat->lastCharacterUpdate = GetTime(); } void clearInteractionChat(InteractionChat* chat) { memset(&chat->text, 0, INTERACTION_CHAT_MAX); memset(&chat->displayedText, 0, INTERACTION_CHAT_MAX); chat->textSize = 0; chat->displayUpTo = 0; } bool isInteractionChatAnimationDone(InteractionChat* chat) { return chat->displayUpTo >= chat->textSize; } void endInteractionChatAnimation(InteractionChat* chat) { chat->displayUpTo = chat->textSize; strncpy(chat->displayedText, chat->text, chat->textSize); } void updateInteractionChat(InteractionChat* chat, Game* game) { if (IsWindowResized()) { resizeInteractionChat(chat, &game->settings); } if (!chat->visible) { return; } Color background = DARKGRAY; background.a = game->settings.uiAlpha; DrawRectangleRec(chat->rect, background); float lineThickness = game->settings.uiOutlineSize; float border = lineThickness + 1.0; int fontSize = game->settings.interactionFontSize; DrawRectangleLinesEx(chat->rect, lineThickness, BLACK); // Do cool animation. double currentTime = GetTime(); if (chat->displayUpTo < chat->textSize && currentTime - chat->lastCharacterUpdate >= game->settings.interactionChatAnimationSpeed) { chat->lastCharacterUpdate = currentTime; chat->displayedText[chat->displayUpTo] = chat->text[chat->displayUpTo]; ++chat->displayUpTo; } // Draw text. if (chat->entityId != ENTITY_NONE) { DrawText(TextFormat("%s says:", getEntityName(chat->entityId)), chat->rect.x + border, chat->rect.y + border, fontSize, WHITE); } DrawText(chat->displayedText, chat->rect.x + border, chat->rect.y + (border * 2.0) + fontSize, fontSize, GREEN); DrawText("Hit enter to continue...", chat->rect.x + border, chat->rect.y + chat->rect.height - fontSize - border, fontSize, WHITE); } void resizeInteractionMenu(InteractionMenu* menu, const Settings* settings) { menu->rect.width = settings->interactionMenuWidth; menu->rect.height = (INTERACTION_MENU_MAX + 4) * settings->interactionFontSize; menu->rect.x = 0.0; menu->rect.y = GetRenderHeight() - settings->interactionChatHeight - menu->rect.height - settings->uiOutlineSize; } void initInteractionMenu(InteractionMenu* menu, const Settings* settings) { resetInteractionMenu(menu); resizeInteractionMenu(menu, settings); menu->visible = false; menu->entityId = ENTITY_NONE; } void setInteractionMenu(InteractionMenu* menu, const InteractionItems items, int itemCount) { // Check for out of bounds. if (itemCount > INTERACTION_MENU_MAX) { TraceLog(LOG_ERROR, "itemCount > INTERACTION_MENU_MAX"); return; } menu->itemCount = itemCount; for (int index = 0; index < itemCount; ++index) { strncpy(menu->items[index], items[index], INTERACTION_LABEL_MAX - 1); } } void resetInteractionMenu(InteractionMenu* menu) { for (int index = 0; index < INTERACTION_MENU_MAX; ++index) { memset(menu->items[index], 0, INTERACTION_LABEL_MAX); } menu->itemCount = 0; } void showInteractionMenu(InteractionMenu* menu) { menu->visible = true; } void hideInteractionMenu(InteractionMenu* menu) { menu->visible = false; } void updateInteractionMenu(InteractionMenu* menu, Game* game) { if (IsWindowResized()) { resizeInteractionMenu(menu, &game->settings); } if (!menu->visible) { return; } // Draw background. Color background = DARKGRAY; background.a = game->settings.uiAlpha; DrawRectangleRec(menu->rect, background); float lineThickness = game->settings.uiOutlineSize; float border = lineThickness + 1.0; int fontSize = game->settings.interactionFontSize; DrawRectangleLinesEx(menu->rect, lineThickness, BLACK); Vector2 position = (Vector2){menu->rect.x + border, menu->rect.y + border}; // Draw top information. DrawText("Press a number key to select", position.x, position.y, fontSize, WHITE); position.y += fontSize + fontSize; // Draw items. for (int index = 0; index < menu->itemCount; ++index) { DrawText(TextFormat("%d: ", index + 1), position.x, position.y, fontSize, WHITE); DrawText(TextFormat(" %s", menu->items[index]), position.x, position.y, fontSize, GREEN); position.y += fontSize; } } void resizeInventory(Inventory* inventory, const Settings* settings) { float outlineThickness = settings->uiOutlineSize; float spriteSize = INVENTORY_SPRITE_SIZE * INVENTORY_SCALE; inventory->rect.width = INVENTORY_COLUMNS * spriteSize + outlineThickness; inventory->rect.height = INVENTORY_ROWS * spriteSize + outlineThickness; inventory->rect.x = GetRenderWidth() / 2.0 - inventory->rect.width / 2.0; inventory->rect.y = GetRenderHeight() / 2.0 - inventory->rect.height / 2.0; } void initInventory(Inventory* inventory, const Settings* settings) { resizeInventory(inventory, settings); inventory->visable = false; inventory->itemCount = 0; } void showInventory(Inventory* inventory, Game* game) { inventory->visable = true; enableGameCursor(game); } void hideInventory(Inventory* inventory, Game* game) { inventory->visable = false; disableGameCursor(game); } void addItemToInventory(Inventory* inventory, InventoryItem item) { // If item is already in the inventory. for (int index = 0; index < inventory->itemCount; ++index) { if (inventory->items[index].id == item.id) { inventory->items[index].count += item.count; return; } } // Add item to inventory. if (inventory->itemCount >= INVENTORY_MAX) { TraceLog(LOG_ERROR, "inventory->itemCount >= INVENTORY_MAX"); } else { inventory->items[inventory->itemCount] = item; ++inventory->itemCount; } } void removeInventoryItem(Inventory* inventory, int itemIndex) { // Out of bounds. if (itemIndex < 0 || itemIndex >= inventory->itemCount) { return; } // Decrease count. InventoryItem* item = &inventory->items[itemIndex]; --item->count; // Remove item if no more. if (item->count <= 0) { for (int index = itemIndex; index < inventory->itemCount - 1; ++index) { inventory->items[index] = inventory->items[index + 1]; } --inventory->itemCount; // Might prevent a future bug or something :D if (inventory->itemCount < 0) { inventory->itemCount = 0; } } } void updateInventory(Inventory* inventory, Game* game) { if (IsWindowResized()) { resizeInventory(inventory, &game->settings); } // Handle toggle key. if (IsKeyPressed(game->settings.toggleInventoryKey)) { if (inventory->visable) { hideInventory(inventory, game); } else { showInventory(inventory, game); } } if (!inventory->visable) { return; } // Draw background. float outlineThickness = game->settings.uiOutlineSize; Color backgroundColor = PINK; backgroundColor.a = game->settings.uiAlpha; DrawRectangleRec(inventory->rect, backgroundColor); DrawRectangleLinesEx(inventory->rect, outlineThickness, BLACK); float spriteSize = INVENTORY_SPRITE_SIZE * INVENTORY_SCALE; int startX = inventory->rect.x + outlineThickness; int startY = inventory->rect.y + outlineThickness; int maxX = inventory->rect.width + inventory->rect.x - spriteSize; int maxY = inventory->rect.height + inventory->rect.y - spriteSize; int x = startX; int y = startY; int fontSize = spriteSize / 3.0; // Mouse stuff. Vector2 mousePosition = GetMousePosition(); int mouseRow = (mousePosition.y - inventory->rect.y) / spriteSize; int mouseColumn = (mousePosition.x - inventory->rect.x) / spriteSize; bool mouseIsSelecting = mouseRow >= 0 && mouseRow < (inventory->rect.height / spriteSize) - 1 && mouseColumn >= 0 && mouseColumn < (inventory->rect.width / spriteSize) - 1; if (mouseIsSelecting) { // Draw selection DrawRectangleLinesEx( (Rectangle){ mouseColumn * spriteSize + inventory->rect.x, mouseRow * spriteSize + inventory->rect.y, spriteSize, spriteSize }, outlineThickness, BLACK); } int row = 0; int column = 0; bool killItem = false; int killIndex = 0; // Draw items. for (int index = 0; index < inventory->itemCount; ++index) { InventoryItem* item = &inventory->items[index]; Color color = WHITE; // Item Is selected. if (mouseIsSelecting && row == mouseRow && column == mouseColumn) { // Make it blink when selected. if ((int)(GetTime() / game->settings.inventoryItemBlinkSpeed) % 2 == 0) { color = item->blinkColor; } // Use item. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { killItem = interactWithEntity(item->parent, game, SELECTION_USE) == INTERACTION_KILL_ITEM; killIndex = index; } } DrawTextureEx(game->assets.textures[item->textureId], (Vector2){x, y}, 0.0, INVENTORY_SCALE, color); // Draw count. if (item->count > 1) { DrawText(TextFormat("%d", item->count), x, y, fontSize, BLACK); } x += spriteSize; ++column; if (x >= maxX) { x = startX; y += spriteSize; ++row; column = 0; } } if (killItem) { removeInventoryItem(inventory, killIndex); } }