Untitled

 avatar
unknown
plain_text
a year ago
77 kB
12
Indexable
using Assimp;
using Graven.Engine;
using Graven.Properties;
using OpenTK;
using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Input;
using OpenTK.Mathematics;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
using Button = System.Windows.Forms.Button;
using Image = System.Drawing.Image; // For GraphicsPath
using Keys = System.Windows.Forms.Keys;
using ProgressBar = System.Windows.Forms.ProgressBar;
using Timer = System.Windows.Forms.Timer;
using ToolTip = System.Windows.Forms.ToolTip;



namespace Graven
{
    public partial class Game : Form
    {
        private RenderForm rnd;


        #region Inventory system
        private const int ROWS = 5; // 4 inventory + 1 hotbar
        private const int COLS = 8;
        private const int TOTAL_SLOTS = ROWS * COLS;
        private const int MAX_STACK = 64;

        private Panel p_inventory;
        private Panel p_hotbar;
        private PictureBox[] allSlots;
        private InventoryItem[] allItems;
        private int selectedSlot = 0;

        private PictureBox draggedItem;
        private DragInfo dragInfo;
        private Point dragOffset;
        private Panel craftPanel; // <-- your CraftPanel

        private ToolTip slotTooltip;
        private ContextMenuStrip slotMenu;
        private Image emptySlotIcon = Properties.Resources.Slot;

        public  bool inventoryVisible = false;
        private bool isTesting = false;

        // Loader panel
        private Panel loaderPanel;
        private PictureBox loaderImage;
        private Label loaderText;


        //Console
        private Panel panel_Console;
        private System.Windows.Forms.TextBox tb_CommandInput;
        private RichTextBox rtb_Console;
        private System.Windows.Forms.Button btn_executeCommand;

        private Label lootboxLabel = null;
        private const float LOOTBOX_RADIUS = 2.5f; // distance to show label

        private int HaveAmount1, HaveAmount2, HaveAmount3;

        private Form dragForm; // top-level transparent form

        private Stopwatch frameTimer = new Stopwatch();
        private double lastFrameTime;


        private class DragInfo
        {
            public int Index;       // -1 for loot
            public InventoryItem Item;
            public LootSlot LootSlot; // null if dragging from inventory
            public Point Offset;
        }

        #endregion


        private Panel lootPanel;
        private LootSlot[,] lootSlots;


        #region setup Loader
        private void InitLoaderPanel()
        {
            loaderPanel = new Panel
            {
                Dock = DockStyle.Fill,
                BackColor = Color.Black
            };

            // Background image
            loaderImage = new PictureBox
            {
                Dock = DockStyle.Fill,
                Image = Properties.Resources.Loader, // your image
                SizeMode = PictureBoxSizeMode.StretchImage
            };
            loaderPanel.Controls.Add(loaderImage);

            // Status text
            loaderText = new Label
            {
                Text = "Starting...",
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 18, FontStyle.Bold),
                AutoSize = false,
                TextAlign = ContentAlignment.MiddleCenter,
                Dock = DockStyle.Bottom,
                Height = 60,
                BackColor = Color.Transparent
            };
            loaderPanel.Controls.Add(loaderText);

            this.Controls.Add(loaderPanel);
            loaderPanel.BringToFront();
        }

        private void SetLoaderText(string text)
        {
            if (loaderText.InvokeRequired)
            {
                loaderText.Invoke(new Action(() => loaderText.Text = text));
            }
            else
            {
                loaderText.Text = text;
            }
            loaderPanel.Refresh();
        }


        #endregion

        public Game()
        {
            this.FormBorderStyle = FormBorderStyle.None;
            this.WindowState = FormWindowState.Maximized;
            this.BackColor = Color.Black;
            this.Text = "Graven - Survival Game";

            InitLoaderPanel(); // show loader first
            RunLoaderAsync();
        }

        private async Task RunLoaderAsync()
        {
            loaderPanel.Visible = true;
            loaderPanel.BringToFront();

            // Run setup steps that don't require the RenderForm to exist
            await ShowStep("Setting up inventory...", SetupSlots);
            await ShowStep("Setting up loot...", SetupExampleItems);                  // actual loot UI created after rnd below
            await ShowStep("Creating craft menu...", CreateCraftMenu);
            await ShowStep("Setting up tooltips...", SetupTooltipsAndContext);
            await ShowStep("Setting up lootable UI...", SetupLootPanel);
            await ShowStep("Loading world...");
            await ShowStep("Setting Up World");
            await ShowStep("Finalizing...");

            // Hide loader
            loaderPanel.Visible = false;


            InitConsole();
            InitHealthBox();
            InitStatusBars();
            StartStatusUpdater();
            // InitOverlay();

            // Create RenderForm and add it to the form
            rnd = new RenderForm
            {
                TopLevel = false,
                FormBorderStyle = FormBorderStyle.None,
                Dock = DockStyle.Fill
            };
            this.Controls.Add(rnd);
            rnd.BringToFront();

            

            // Make sure other UI controls (inventory, hotbar, panels) are above the render form
            foreach (Control c in this.Controls)
                if (!(c is RenderForm))
                    c.BringToFront();

            // Layout hooks
            this.Resize += (s, e) => PositionPanels();
            PositionPanels();

            dragForm = new Form();
            dragForm.FormBorderStyle = FormBorderStyle.None;
            dragForm.TopMost = true;
            dragForm.ShowInTaskbar = false;
            dragForm.BackColor = Color.Lime;       // any color you want to be transparent
            dragForm.TransparencyKey = Color.Lime; // match the BackColor
            dragForm.StartPosition = FormStartPosition.Manual;
            dragForm.Size = this.Size;
            dragForm.Location = this.Location;
            dragForm.Show();

            // Make sure it moves with the main form
            this.LocationChanged += (s, e) => dragForm.Location = this.Location;
            this.SizeChanged += (s, e) => dragForm.Size = this.Size;


            // Finalize
            CraftManager.craftableItems(this);
            this.KeyPreview = true;
            this.KeyDown += Game_KeyDown;
            rnd.Show();
        }

        private async Task ShowStep(string message, Action action = null)
        {
            SetLoaderText(message);
            await Task.Delay(500); // give user a moment to see the text
            action?.Invoke();
        }


  

        private void Game_Load(object sender, EventArgs e)
        {

        }


        private void Updater_Tick(object sender, EventArgs e)
        {
            UpdateLootboxLabel();
            UpdateCraftInfo(); // <-- refresh craft info in real time

            double now = frameTimer.Elapsed.TotalSeconds;
            float dt = (float)(now - lastFrameTime);
            lastFrameTime = now;

            this.Invalidate(); // trigger Paint

            // UpdateFloatingLabels(dt); // <-- Add this at the end of UpdateLogic
        }



        #region healthbarOfObjects
        // In your Game Form constructor or Load method
        Panel healthBox = new Panel();
        Panel healthBar = new Panel();

        private void InitHealthBox()
        {
            // Create the container
            healthBox.Size = new Size(120, 20);

            // Center it on the form
            healthBox.Location = new Point(
                (this.ClientSize.Width - healthBox.Width) / 2,
                (this.ClientSize.Height - healthBox.Height) / 2
            );

            healthBox.BackColor = Color.DarkGray; // background color

            // Create the health bar
            healthBar = new Panel();
            healthBar.Size = new Size(120, 20); // full width initially
            healthBar.BackColor = Color.White; // health bar color
            healthBox.Visible = false; // hidden by default


            // Add the bar to the box
            healthBox.Controls.Add(healthBar);
            this.Controls.Add(healthBox);

            // Optional: make sure it stays centered if the form is resized
            this.Resize += (s, e) =>
            {
                healthBox.Location = new Point(
                    (this.ClientSize.Width - healthBox.Width) / 2,
                    (this.ClientSize.Height - healthBox.Height) / 2
                );
            };

            healthBar.Visible = false;
        }

        private void UpdateHealthBar(int currentHealth, int maxHealth)
        {
            float percent = (float)currentHealth / maxHealth;
            healthBar.Width = (int)(healthBox.Width * percent);
        }

        private void ShowHealthBar(int currentHealth, int maxHealth)
        {
            healthBox.Visible = true;
            healthBar.Visible = true;
            UpdateHealthBar(currentHealth, maxHealth);
        }

        private void HideHealthBar()
        {
            healthBox.Visible = false;
            healthBar.Visible = false;
        }

        #endregion

        #region PlayerStatusBars

        // Panels for containers + bars
        private Panel healthBoxs, healthBars;
        private Panel foodBox, foodBar;
        private Panel waterBox, waterBar;

        // Labels
        private Label healthLabel, foodLabel, waterLabel;

        // Player stats
        private int currentHealth = 100;
        private int maxHealth = 100;

        private int currentFood = 100;
        private int maxFood = 100;

        private int currentWater = 100;
        private int maxWater = 100;

        // Timer for survival updates
        private System.Windows.Forms.Timer statusTimer;

        public void ModifyFood(int amount)
        {
            currentFood = Math.Clamp(currentFood + amount, 0, maxFood);
            RefreshStatusBars();
        }

        public void ModifyWater(int amount)
        {
            currentWater = Math.Clamp(currentWater + amount, 0, maxWater);
            RefreshStatusBars();
        }

        private void InitStatusBars()
        {
            int barWidth = 150;
            int barHeight = 18;
            int spacing = 6; // spacing between bars
            int labelWidth = 50;

            // -------------------------
            // HEALTH
            // -------------------------
            healthBoxs = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.DarkGray
            };
            healthBars = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.Red
            };
            healthBoxs.Controls.Add(healthBars);

            healthLabel = new Label
            {
                Text = "❤️",
                Size = new Size(labelWidth, barHeight),
                ForeColor = Color.White,
                BackColor = Color.Red,
                Font = new Font("Arial", 10, FontStyle.Bold),
                TextAlign = ContentAlignment.MiddleLeft
            };
            this.Controls.Add(healthLabel);

            // -------------------------
            // FOOD
            // -------------------------
            foodBox = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.DarkGray
            };
            foodBar = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.Orange
            };
            foodBox.Controls.Add(foodBar);

            foodLabel = new Label
            {
                Text = "🍗",
                Size = new Size(labelWidth, barHeight),
                ForeColor = Color.White,
                BackColor = Color.Orange,
                Font = new Font("Arial", 10, FontStyle.Bold),
                TextAlign = ContentAlignment.MiddleLeft
            };
            this.Controls.Add(foodLabel);

            // -------------------------
            // WATER
            // -------------------------
            waterBox = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.DarkGray
            };
            waterBar = new Panel
            {
                Size = new Size(barWidth, barHeight),
                BackColor = Color.DodgerBlue
            };
            waterBox.Controls.Add(waterBar);

            waterLabel = new Label
            {
                Text = "🥛",
                Size = new Size(labelWidth, barHeight),
                ForeColor = Color.White,
                BackColor = Color.DodgerBlue,
                Font = new Font("Arial", 10, FontStyle.Bold),
                TextAlign = ContentAlignment.MiddleLeft
            };
            this.Controls.Add(waterLabel);

            // Add panels to form
            this.Controls.Add(healthBoxs);
            this.Controls.Add(foodBox);
            this.Controls.Add(waterBox);

            // Position bars and labels
            PositionStatusBars(barWidth, barHeight, spacing, labelWidth);

            // Adjust on resize
            this.Resize += (s, e) => PositionStatusBars(barWidth, barHeight, spacing, labelWidth);

            // Initialize UI with current stats
            RefreshStatusBars();

            // Start hunger/thirst loop
            StartStatusUpdater();
        }

        private void PositionStatusBars(int width, int height, int spacing, int labelWidth)
        {
            int margin = 12; // distance from edge
            int bottom = this.ClientSize.Height - margin - height;

            // Water at top
            waterBox.Location = new Point(margin + labelWidth, bottom - (height + spacing) * 2);
            waterLabel.Location = new Point(margin, bottom - (height + spacing) * 2);

            // Food in middle
            foodBox.Location = new Point(margin + labelWidth, bottom - (height + spacing) * 1);
            foodLabel.Location = new Point(margin, bottom - (height + spacing) * 1);

            // Health at bottom
            healthBoxs.Location = new Point(margin + labelWidth, bottom - (height + spacing) * 0);
            healthLabel.Location = new Point(margin, bottom - (height + spacing) * 0);
        }

        private void UpdateBar(Panel bar, Panel box, int current, int max)
        {
            float percent = Math.Max(0, Math.Min(1f, (float)current / max));
            bar.Width = (int)(box.Width * percent);
        }

        // Refresh all bars
        private void RefreshStatusBars()
        {
            UpdateBar(healthBars, healthBoxs, currentHealth, maxHealth);
            UpdateBar(foodBar, foodBox, currentFood, maxFood);
            UpdateBar(waterBar, waterBox, currentWater, maxWater);
        }

        // Example methods to change stats
        public void DamagePlayer(int amount)
        {
            currentHealth = Math.Max(0, currentHealth - amount);
            RefreshStatusBars();
        }

        public void HealPlayer(int amount)
        {
            currentHealth = Math.Min(maxHealth, currentHealth + amount);
            RefreshStatusBars();
        }

        public void EatFood(int amount)
        {
            currentFood = Math.Min(maxFood, currentFood + amount);
            RefreshStatusBars();
        }

        public void DrinkWater(int amount)
        {
            currentWater = Math.Min(maxWater, currentWater + amount);
            RefreshStatusBars();
        }

        // ----------------------------
        // Survival updater loop
        // ----------------------------
        private void StartStatusUpdater()
        {
            statusTimer = new System.Windows.Forms.Timer();
            statusTimer.Interval = 1000; // 1 second
            statusTimer.Tick += (s, e) =>
            {
                // Reduce food + water
                currentFood = Math.Max(0, currentFood - 1);
                currentWater = Math.Max(0, currentWater - 2); // lose water faster

                // If starving or dehydrated, take health damage
                if (currentFood <= 0) DamagePlayer(1);
                if (currentWater <= 0) DamagePlayer(2);

                RefreshStatusBars();
            };
            statusTimer.Start();
        }

        #endregion


        #region CraftMenu System

        // --- Fields ---
        private Panel CraftPanel;
        private Panel panel_CraftInfo;
        private NumericUpDown CraftAmount;
        private Label CM_ItemName, CM_Desc;
        private PictureBox CM_ItemImage;
        private Button Btn_CraftItem;

        private PictureBox[] CM_RP_ITEM_Images;
        private Label[] CM_RP_LblAmounts;
        private Label[] CM_HaveAmounts;

        private TabControl tabControl;
        private Recipe currentRecipe;

        // --- Recipe ---
        public class Recipe
        {
            public string ResultName;
            public Image ResultIcon;
            public string Description;
            public ItemType ResultType { get; set; } // <-- added type
            public (string itemName, Image icon, int amountNeeded)[] Requirements;
            public int TabIndex; // Which tab it belongs in
        }
        private void ResetCraftInfo()
        {
            currentRecipe = null;
            panel_CraftInfo.Visible = false;

            CM_ItemImage.Image = null;
            CM_ItemName.Text = "";
            CM_Desc.Text = "";

            for (int i = 0; i < 3; i++)
            {
                CM_RP_ITEM_Images[i].Visible = false;
                CM_RP_LblAmounts[i].Visible = false;
                CM_RP_LblAmounts[i].Text = "";     // ← reset text
                CM_HaveAmounts[i].Visible = false;
                CM_HaveAmounts[i].Text = "";       // ← reset text
            }

            CraftAmount.Value = 1;
            CraftAmount.Maximum = 99;
        }

        private int MaxCraftableAmount()
        {
            if (currentRecipe == null) return 1;

            int maxAmount = int.MaxValue;

            foreach (var req in currentRecipe.Requirements)
            {
                int have = CountInInventory(req.itemName);
                int maxForThis = have / req.amountNeeded;
                if (maxForThis < maxAmount)
                    maxAmount = maxForThis;
            }

            return Math.Max(1, maxAmount); // at least 1
        }

        // --- Create Craft Menu (call once in Game_Load) ---
        public void CreateCraftMenu()
        {
            CraftPanel = new Panel
            {
                Size = new Size(920, 500),
                Location = new Point(490, 120),
                BackColor = Color.Black,
                BorderStyle = BorderStyle.FixedSingle,
                Visible = false
            };

            // Tab Control
            tabControl = new TabControl
            {
                Size = new Size(470, 460),
                Location = new Point(10, 10),
                Font = new Font("Segoe UI", 12, FontStyle.Bold)
                
            };

            string[] tabIcons = { "🍁", "⛏", "⚒️", "💊", "⛊", "📐" };
            foreach (var icon in tabIcons)
            {
                TabPage tab = new TabPage(icon) { BackColor = Color.Black };
                tabControl.TabPages.Add(tab);
            }

            CraftPanel.Controls.Add(tabControl);

            // Craft Info Panel
            panel_CraftInfo = new Panel
            {
                Size = new Size(400, 460),
                Location = new Point(480, 10),
                BackColor = Color.Black,
                BorderStyle = BorderStyle.Fixed3D,
                Visible = false
            };

            CM_ItemImage = new PictureBox
            {
                Size = new Size(100, 100),
                Location = new Point(20, 20),
                SizeMode = PictureBoxSizeMode.Zoom
            };
            panel_CraftInfo.Controls.Add(CM_ItemImage);

            CM_ItemName = new Label
            {
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 14, FontStyle.Bold),
                Location = new Point(140, 20),
                AutoSize = true
            };
            panel_CraftInfo.Controls.Add(CM_ItemName);

            CM_Desc = new Label
            {
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 10),
                Size = new Size(360, 60),
                Location = new Point(20, 130)
            };
            panel_CraftInfo.Controls.Add(CM_Desc);

            Label lblAmount = new Label
            {
                Text = "Amount:",
                ForeColor = Color.White,
                Font = new Font("Segoe UI", 11),
                Location = new Point(20, 200),
                AutoSize = true
            };
            panel_CraftInfo.Controls.Add(lblAmount);

            CraftAmount = new NumericUpDown
            {
                Minimum = 1,
                Maximum = 99,
                Value = 1,
                Font = new Font("Segoe UI", 11, FontStyle.Bold),
                Size = new Size(70, 30),
                Location = new Point(100, 195),
                TextAlign = HorizontalAlignment.Center
            };
            panel_CraftInfo.Controls.Add(CraftAmount);

            // Requirement slots (max 3)
            CM_RP_ITEM_Images = new PictureBox[3];
            CM_RP_LblAmounts = new Label[3];
            CM_HaveAmounts = new Label[3];

            int yOffset = 240;
            for (int i = 0; i < 3; i++)
            {
                CM_RP_ITEM_Images[i] = new PictureBox
                {
                    Size = new Size(40, 40),
                    Location = new Point(20, yOffset),
                    SizeMode = PictureBoxSizeMode.Zoom
                };
                panel_CraftInfo.Controls.Add(CM_RP_ITEM_Images[i]);

                CM_RP_LblAmounts[i] = new Label
                {
                    ForeColor = Color.Maroon,
                    Font = new Font("Segoe UI Black", 12, FontStyle.Bold),
                    Location = new Point(70, yOffset + 5),
                    AutoSize = true
                };
                panel_CraftInfo.Controls.Add(CM_RP_LblAmounts[i]);

                CM_HaveAmounts[i] = new Label
                {
                    ForeColor = Color.Green,
                    Font = new Font("Segoe UI Black", 12, FontStyle.Bold),
                    Location = new Point(120, yOffset + 5),
                    AutoSize = true
                };
                panel_CraftInfo.Controls.Add(CM_HaveAmounts[i]);

                yOffset += 60;
            }

            Btn_CraftItem = new Button
            {
                Text = "CRAFT ITEM",
                ForeColor = Color.White,
                BackColor = Color.FromArgb(70, 70, 70),
                FlatStyle = FlatStyle.Flat,
                Font = new Font("Segoe UI", 12, FontStyle.Bold),
                Size = new Size(360, 40),
                Location = new Point(20, 400)
            };
            panel_CraftInfo.Controls.Add(Btn_CraftItem);

            Btn_CraftItem.Click += CraftItem;
            CraftPanel.Controls.Add(panel_CraftInfo);
            this.Controls.Add(CraftPanel);
            CraftPanel.BringToFront();


        }

        private int CountInInventory(string itemName)
        {
            int count = 0;
            foreach (var item in allItems)
            {
                if (item != null && item.Name == itemName)
                    count += item.Count;
            }
            return count;
        }


        private void RemoveFromInventory(string itemName, int amount)
        {
            for (int i = 0; i < allItems.Length; i++)
            {
                var item = allItems[i];
                if (item != null && item.Name == itemName)
                {
                    if (item.Count > amount)
                    {
                        item.Count -= amount;
                        allSlots[i].Invalidate();
                        return;
                    }
                    else
                    {
                        amount -= item.Count;
                        allItems[i] = null;
                        allSlots[i].Invalidate();
                        if (amount <= 0)
                            return;
                    }
                }
            }
        }


        // --- Add Recipe to Menu ---
        public void AddToCraftMenu(Recipe recipe)
        {
            int tabIndex = recipe.TabIndex;
            if (tabIndex < 0 || tabIndex >= tabControl.TabPages.Count)
                tabIndex = 0;

            // Create clickable icon
            PictureBox itemIcon = new PictureBox
            {
                Size = new Size(60, 60),
                SizeMode = PictureBoxSizeMode.Zoom,
                Image = recipe.ResultIcon,
                Cursor = Cursors.Hand
            };

            // Position it (simple flow layout)
            int count = tabControl.TabPages[tabIndex].Controls.Count;
            int x = 20 + (count % 6) * 70;
            int y = 20 + (count / 6) * 70;
            itemIcon.Location = new Point(x, y);

            tabControl.TabPages[tabIndex].Controls.Add(itemIcon);

            // Click to show recipe
            itemIcon.Click += (s, e) => ShowRecipe(recipe);
        }

        // --- Show selected recipe ---
        private void ShowRecipe(Recipe recipe)
        {
            currentRecipe = recipe;
            panel_CraftInfo.Visible = true;

            CM_ItemImage.Image = recipe.ResultIcon;
            CM_ItemName.Text = recipe.ResultName;
            CM_Desc.Text = recipe.Description;

            for (int i = 0; i < 3; i++)
            {
                if (i < recipe.Requirements.Length)
                {
                    CM_RP_ITEM_Images[i].Visible = true;
                    CM_RP_ITEM_Images[i].Image = recipe.Requirements[i].icon;

                    CM_RP_LblAmounts[i].Visible = true;
                    CM_RP_LblAmounts[i].Text = recipe.Requirements[i].amountNeeded.ToString();

                    int have = CountInInventory(recipe.Requirements[i].itemName);
                    CM_HaveAmounts[i].Visible = true;
                    CM_HaveAmounts[i].Text = "/ " + have;

                    // ✅ Set color: green if enough, red if not
                    if (have >= recipe.Requirements[i].amountNeeded)
                        CM_HaveAmounts[i].ForeColor = Color.Green;
                    else
                        CM_HaveAmounts[i].ForeColor = Color.Maroon;
                }
                else
                {
                    CM_RP_ITEM_Images[i].Visible = false;
                    CM_RP_LblAmounts[i].Visible = false;
                    CM_RP_LblAmounts[i].Text = "";
                    CM_HaveAmounts[i].Visible = false;
                    CM_HaveAmounts[i].Text = "";
                }
            }
            UpdateCraftInfo(); // Refresh counts
        }

        // --- Craft button logic ---
        private void CraftItem(object sender, EventArgs e)
        {
            if (currentRecipe == null) return;
            int craftCount = (int)CraftAmount.Value;

            foreach (var req in currentRecipe.Requirements)
            {
                int have = CountInInventory(req.itemName);
                if (have < req.amountNeeded * craftCount)
                {
                    return;
                }
            }

            foreach (var req in currentRecipe.Requirements)
                RemoveFromInventory(req.itemName, req.amountNeeded * craftCount);

            AddItem(new InventoryItem
            {
                Name = currentRecipe.ResultName,
                Icon = currentRecipe.ResultIcon,
                Count = craftCount,
                Type = currentRecipe.ResultType
            });

            UpdateCraftInfo(); // Refresh counts
        }

        private void UpdateCraftInfo()
        {
            if (currentRecipe == null || !panel_CraftInfo.Visible)
                return;

            for (int i = 0; i < currentRecipe.Requirements.Length; i++)
            {
                var req = currentRecipe.Requirements[i];
                int have = CountInInventory(req.itemName);

                CM_HaveAmounts[i].Text = "/ " + have;
                CM_HaveAmounts[i].ForeColor = have >= req.amountNeeded * (int)CraftAmount.Value
                                             ? Color.Green
                                             : Color.Maroon;
            }

            // Update max craftable amount
            CraftAmount.Maximum = MaxCraftableAmount();
            if (CraftAmount.Value > CraftAmount.Maximum)
                CraftAmount.Value = CraftAmount.Maximum;
        }

        #endregion



     



        #region Console Setup

        private void InitConsole()
        {
            panel_Console = new Panel
            {
                BackColor = Color.FromArgb(200, 0, 0, 0), // semi-transparent black
                Size = new Size(500, 300),
                Location = new Point(10, this.ClientSize.Height - 290),
                Visible = false // hidden by default
            };

            rtb_Console = new RichTextBox
            {
                BackColor = Color.Black,
                ForeColor = Color.PaleVioletRed,
                BorderStyle = BorderStyle.None,
                Location = new Point(5, 5),
                Size = new Size(490, 250),
                ReadOnly = true
            };

            tb_CommandInput = new System.Windows.Forms.TextBox
            {
                Location = new Point(5, 265),
                Size = new Size(400, 23),
                BorderStyle = BorderStyle.FixedSingle
            };

            btn_executeCommand = new System.Windows.Forms.Button
            {
                Text = "Execute",
                Location = new Point(410, 264),
                Size = new Size(80, 25),
                ForeColor = Color.White
            };

            btn_executeCommand.Click += ExecuteCommand;
            tb_CommandInput.KeyDown += Tb_CommandInput_KeyDown;

            panel_Console.Controls.Add(rtb_Console);
            panel_Console.Controls.Add(tb_CommandInput);
            panel_Console.Controls.Add(btn_executeCommand);

            this.Controls.Add(panel_Console);
        }


        private void Tb_CommandInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                ExecuteCommand(sender, EventArgs.Empty);
                e.SuppressKeyPress = true; // stop ding sound
            }
        }

        private void ExecuteCommand(object sender, EventArgs e)
        {
            string cmd = tb_CommandInput.Text.Trim();
            if (string.IsNullOrEmpty(cmd)) return;

            // log command
            rtb_Console.AppendText($"> {cmd}\n");

            // handle commands (basic example)
            string response = GiveHelper.HandleCommand(cmd, this);
            rtb_Console.AppendText(response + "\n");

            tb_CommandInput.Clear();
        }

        #endregion


        #region lootbox setup and logic

        private Panel dragLayer;
        private Label lootTitle;


        private PictureBox lootDraggedItem;
        private Label lootDraggedCount;
        private LootSlot lootDragInfo;
        private Point lootDragOffset;



        // Either rename the methods
        private void LootSlot_MouseMove(object sender, MouseEventArgs e)
        {
            LootDraggedItem_MouseMove(sender, e);
        }

        private void LootSlot_MouseUp(object sender, MouseEventArgs e)
        {
            LootDraggedItem_MouseUp(sender, e);
        }

        public Point WorldToScreen(Vector3 worldPos)
        {
            Vector4 clipSpacePos = new Vector4(worldPos, 1f);

            Matrix4 view = rnd.camera.GetViewMatrix();
            Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(
                MathHelper.DegreesToRadians(70f),
                Math.Max(1, rnd.Width) / (float)Math.Max(1, rnd.Height),
                0.1f, 1000f
            );

            clipSpacePos = Vector4.TransformRow(clipSpacePos, view);
            clipSpacePos = Vector4.TransformRow(clipSpacePos, projection);

            if (clipSpacePos.W != 0)
            {
                clipSpacePos.X /= clipSpacePos.W;
                clipSpacePos.Y /= clipSpacePos.W;
                clipSpacePos.Z /= clipSpacePos.W;
            }

            int x = (int)((clipSpacePos.X * 0.5f + 0.5f) * this.ClientSize.Width);
            int y = (int)((-clipSpacePos.Y * 0.5f + 0.5f) * this.ClientSize.Height);

            return new Point(x, y);
        }

        public int AddItemPartial(InventoryItem newItem)
        {
            int remaining = newItem.Count;

            for (int i = 0; i < allItems.Length; i++)
            {
                var slot = allItems[i];

                if (slot == null)
                {
                    allItems[i] = new InventoryItem
                    {
                        Name = newItem.Name,
                        Icon = newItem.Icon,
                        Type = newItem.Type,
                        Count = remaining,
                        UID = newItem.UID
                    };
                    allSlots[i].Invalidate();
                    return 0; // all added
                }
                else if (slot.Name == newItem.Name &&
                         slot.Type != ItemType.Weapon &&
                         slot.Type != ItemType.common_painting)
                {
                    int space = MAX_STACK - slot.Count;
                    int toAdd = Math.Min(space, remaining);
                    slot.Count += toAdd;
                    remaining -= toAdd;
                    allSlots[i].Invalidate();
                    if (remaining <= 0) return 0;
                }
            }

            return remaining; // leftover if inventory full
        }

        private void SetupLootPanel()
        {
            lootPanel = new Panel()
            {
                Size = new Size(8 * 60 + 10, 2 * 60 + 20),
                Location = new Point(p_inventory.Right + 10, p_inventory.Top),
                BackColor = Color.FromArgb(150, 50, 50, 50),
                Visible = false
            };

            lootTitle = new Label
            {
                Text = "[LootBox] Press R to take all",
                ForeColor = Color.LightYellow,
                BackColor = Color.Transparent,
                Font = new Font("Arial", 10, FontStyle.Bold),
                Location = new Point(0, 0),
                AutoSize = true
            };
            lootPanel.Controls.Add(lootTitle);

            lootSlots = new LootSlot[2, 8];
            int slotSize = 60;
            int padding = 10;

            for (int y = 0; y < 2; y++)
            {
                for (int x = 0; x < 8; x++)
                {
                    PictureBox slot = new PictureBox
                    {
                        Size = new Size(slotSize, slotSize),
                        Location = new Point(x * (slotSize + padding), y * (slotSize + padding) + 20),
                        BackColor = Color.FromArgb(60, 60, 60),
                        SizeMode = PictureBoxSizeMode.StretchImage,
                        Cursor = Cursors.Hand,
                        Tag = new Point(x, y),
                        Image = emptySlotIcon
                    };

                    slot.Paint += LootSlot_Paint;

                    // Drag events
                    slot.MouseDown += LootSlot_MouseDown;
                    slot.MouseMove += LootSlot_MouseMove;
                    slot.MouseUp += LootSlot_MouseUp;

                    lootPanel.Controls.Add(slot);

                    Label countLabel = new Label
                    {
                        Size = new Size(slot.Width, 20),
                        Location = new Point(slot.Left, slot.Bottom - 18),
                        ForeColor = Color.White,
                        BackColor = Color.Transparent,
                        TextAlign = ContentAlignment.BottomRight
                    };
                    lootPanel.Controls.Add(countLabel);

                    lootSlots[y, x] = new LootSlot
                    {
                        IconBox = slot,
                        CountLabel = countLabel,
                        Item = null
                    };
                }
            }

            this.Controls.Add(lootPanel);
        }

        private void OpenLootPanel(LootBox box)
        {
            if (box == null || box.LootItems.Count == 0)
            {
                lootPanel.Visible = false;
                return;
            }

            lootPanel.Visible = true;
            lootPanel.BringToFront();

            foreach (var slot in lootSlots)
            {
                slot.Item = null;
                slot.IconBox.Image = emptySlotIcon;
                slot.CountLabel.Text = "";
            }

            for (int i = 0; i < box.LootItems.Count && i < lootSlots.Length; i++)
            {
                int row = i / lootSlots.GetLength(1);
                int col = i % lootSlots.GetLength(1);
                var item = box.LootItems[i];

                lootSlots[row, col].Item = item;
                lootSlots[row, col].IconBox.Image = item.Icon ?? emptySlotIcon;
                lootSlots[row, col].CountLabel.Text = item.Count > 1 ? item.Count.ToString() : "";
            }

            lootTitle.Text = "[LootBox] Press R to take all";
        }


        private void LootSlot_Paint(object sender, PaintEventArgs e)
        {
            PictureBox slot = sender as PictureBox;
            Point pt = (Point)slot.Tag;
            var lootSlot = lootSlots[pt.Y, pt.X];

            Image icon = lootSlot.Item?.Icon ?? Properties.Resources.Slot;
            e.Graphics.DrawImage(icon, new Rectangle(0, 0, slot.Width, slot.Height));

            if (lootSlot.Item != null && lootSlot.Item.Count > 1)
            {
                using (Brush brush = new SolidBrush(Color.White))
                using (Font font = new Font("Arial", 10, FontStyle.Bold))
                {
                    e.Graphics.DrawString(lootSlot.Item.Count.ToString(), font, brush,
                        new PointF(slot.Width - 18, slot.Height - 18));
                }
            }

            using (Pen pen = new Pen(Color.Yellow, 3))
            using (GraphicsPath path = RoundedRect(new Rectangle(0, 0, slot.Width, slot.Height), 6))
            {
                // Optional: highlight if dragging or selected
                // e.Graphics.DrawPath(pen, path);
            }
        }

        private void LootSlot_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            PictureBox slotBox = sender as PictureBox;
            Point pt = (Point)slotBox.Tag;
            LootSlot slot = lootSlots[pt.Y, pt.X];
            if (slot.Item == null) return;

            // Start dragging
            lootDraggedItem = new PictureBox
            {
                Image = slot.Item.Icon,
                Size = slotBox.Size,
                SizeMode = PictureBoxSizeMode.StretchImage,
                BackColor = Color.Transparent
            };

            lootDraggedCount = new Label
            {
                Text = slot.Item.Count > 1 ? slot.Item.Count.ToString() : "",
                ForeColor = Color.White,
                BackColor = Color.Transparent,
                AutoSize = true
            };

            lootDragInfo = slot;
            lootDragOffset = e.Location;

            this.Controls.Add(lootDraggedItem);
            this.Controls.Add(lootDraggedCount);
            lootDraggedItem.BringToFront();
            lootDraggedCount.BringToFront();

            slot.Item = null; // temporarily remove
            slot.IconBox.Invalidate();
        }


        private void LootDraggedItem_MouseMove(object sender, MouseEventArgs e)
        {
            if (lootDraggedItem == null) return;

            Point mousePos = this.PointToClient(System.Windows.Forms.Cursor.Position);
            lootDraggedItem.Left = mousePos.X - lootDragOffset.X;
            lootDraggedItem.Top = mousePos.Y - lootDragOffset.Y;

            lootDraggedCount.Left = lootDraggedItem.Left;
            lootDraggedCount.Top = lootDraggedItem.Top;
        }

        private void LootDraggedItem_MouseUp(object sender, MouseEventArgs e)
        {
            if (lootDraggedItem == null || lootDragInfo == null) return;

            Point mousePos = System.Windows.Forms.Cursor.Position;

            // Try dropping into inventory
            int leftover = AddItemPartial(new InventoryItem
            {
                Name = lootDragInfo.Item?.Name,
                Icon = lootDragInfo.Item?.Icon,
                Count = lootDragInfo.Item?.Count ?? 1,
                Type = lootDragInfo.Item?.Type ?? ItemType.Resource,
                UID = lootDragInfo.Item?.UID ?? Guid.NewGuid()
            });

            // Clear loot slot visuals
            lootDragInfo.Item = null;
            lootDragInfo.IconBox.Image = Properties.Resources.Slot;
            lootDragInfo.CountLabel.Text = "";

            this.Controls.Remove(lootDraggedItem);
            this.Controls.Remove(lootDraggedCount);
            lootDraggedItem.Dispose();
            lootDraggedCount.Dispose();
            lootDraggedItem = null;
            lootDraggedCount = null;
            lootDragInfo = null;
        }


        private void UpdateLootboxLabel()
        {
            if (RenderForm.nearbyBox != null)
            {
                float dist = (rnd.camera.Position - RenderForm.nearbyBox.Position).Length;

                if (dist <= LOOTBOX_RADIUS)
                {
                    Point screenPos = WorldToScreen(RenderForm.nearbyBox.Position + new Vector3(0, 2f, 0));

                    if (lootboxLabel == null)
                    {
                        lootboxLabel = new Label
                        {
                            Text = "[LootBox] Press R to take all",
                            AutoSize = true,
                            ForeColor = Color.Yellow,
                            BackColor = Color.Transparent
                        };
                        this.Controls.Add(lootboxLabel);
                        lootboxLabel.BringToFront();
                    }

                    lootboxLabel.Left = screenPos.X - lootboxLabel.Width / 2;
                    lootboxLabel.Top = screenPos.Y - lootboxLabel.Height;

                    // Optional: fade based on distance
                    float opacity = Math.Clamp(1 - (dist / LOOTBOX_RADIUS), 0, 1);
                    lootboxLabel.ForeColor = Color.FromArgb((int)(opacity * 255), Color.Yellow);
                }
                else RemoveLootboxLabel();
            }
            else RemoveLootboxLabel();
        }

        private void TakeAllLoot(LootBox box)
        {
            foreach (var item in box.LootItems)
            {
                AddItem(item);
            }
            box.LootItems.Clear();

            foreach (var ls in lootSlots)
            {
                ls.Item = null;
                ls.IconBox.Invalidate();
                ls.CountLabel.Text = "";
            }

            lootPanel.Visible = false;
        }

        private void RemoveLootboxLabel()
        {
            if (lootboxLabel != null)
            {
                this.Controls.Remove(lootboxLabel);
                lootboxLabel.Dispose();
                lootboxLabel = null;
            }
        }

        #endregion


        #region pickup Loot
        private void LootSlot_Click(object sender, EventArgs e)
        {
            PictureBox slot = sender as PictureBox;
            if (slot?.Tag is InventoryItem item)
            {
                if (AddItem(item))
                {
                    slot.Tag = null;
                    slot.Image = null;
                }
            }
        }
        #endregion

        #region Keys
        private void Game_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Tab)
            {
                inventoryVisible = !inventoryVisible;

                // Show/hide inventory UI
                p_inventory.Visible = inventoryVisible;
                CraftPanel.Visible = inventoryVisible;

                // Update RenderForm cursor
                if (rnd != null)
    {
                    rnd.InventoryOpen = inventoryVisible;
                }

                // Reset dragged item
                if (draggedItem != null)
                {
                    // Put it back to its original slot
                    var originalSlot = (PictureBox)draggedItem.Tag; // assume you stored original slot in Tag
                    draggedItem.Location = originalSlot.PointToClient(this.PointToScreen(originalSlot.Location));
                    draggedItem.BringToFront();

                    draggedItem = null;
                }

                if (!inventoryVisible)
                    ResetCraftInfo();
            }

            if (e.KeyCode >= Keys.D1 && e.KeyCode <= Keys.D8)
                SelectSlot(e.KeyCode - Keys.D1);

            if (e.KeyCode == Keys.E)
                UseItem(selectedSlot);

            if (e.KeyCode == Keys.E && RenderForm.nearbyBox != null)
            {
                OpenLootPanel(RenderForm.nearbyBox);
            }

            if (e.KeyCode == Keys.E)
            {
                if (RenderForm.nearbyBox != null)
                {
                    OpenLootPanel(RenderForm.nearbyBox);
                }
            }

            if (e.KeyCode == Keys.R && RenderForm.nearbyBox != null)
            {
                TakeAllLoot(RenderForm.nearbyBox);
                lootPanel.Visible = false;

                // Dispose any dragged item
                if (lootDraggedItem != null)
                {
                    lootDraggedItem.Dispose();
                    lootDraggedItem = null;
                    lootDragInfo = null;
                }
            }


            if (e.KeyCode == Keys.Escape)
            {
                lootPanel.Visible = false;

                inventoryVisible = !inventoryVisible;

                // Show/hide inventory UI
                p_inventory.Visible = inventoryVisible;
                CraftPanel.Visible = inventoryVisible;

                // Update RenderForm cursor
                if(rnd != null)
    {
                    rnd.InventoryOpen = inventoryVisible;
                }

                // Reset dragged item
                if (draggedItem != null)
                {
                    // Put it back to its original slot
                    var originalSlot = (PictureBox)draggedItem.Tag; // assume you stored original slot in Tag
                    draggedItem.Location = originalSlot.PointToClient(this.PointToScreen(originalSlot.Location));
                    draggedItem.BringToFront();

                    draggedItem = null;
                }

                if (!inventoryVisible)
                    ResetCraftInfo();
            }



            if (e.KeyCode == Keys.F)
            {
                // Metal
                if (RenderForm.nearbyMetal != null)
                {
                    RenderForm.nearbyMetal.Mine(this);
                    ShowHealthBar(RenderForm.nearbyMetal.Health, RenderForm.nearbyMetal.MaxHealth);
                    UpdateHealthBar(RenderForm.nearbyMetal.Health, RenderForm.nearbyMetal.MaxHealth);

                    Random rndo = new Random();
                    if (rndo.NextDouble() < 0.04)
                    {
                        ModifyFood(-5);

                    }
                    Random rndo1 = new Random();
                    if (rndo1.NextDouble() < 0.09)
                    {
                        ModifyWater(-5);

                    }


                    if (RenderForm.nearbyMetal.IsDestroyed)
                    {
                        HideHealthBar();
                       
    

                        Random rnds = new Random();
                        if (rnds.NextDouble() < 0.4)
                        {
                            AddItem(new InventoryItem
                            {
                                Name = "Coal",
                                Icon = Properties.Resources.Coal_Icon,
                                Count = 2,
                                Type = ItemType.Resource
                            });
                        }
                    }
                }

                // Bush
                if (RenderForm.nearbyBush != null)
                {
                    RenderForm.nearbyBush.Mine(this);
                    ShowHealthBar(RenderForm.nearbyBush.Health, RenderForm.nearbyBush.MaxHealth);
                    UpdateHealthBar(RenderForm.nearbyBush.Health, RenderForm.nearbyBush.MaxHealth);

                    Random rndo = new Random();
                    if (rndo.NextDouble() < 0.04)
                    {
                        ModifyFood(-5);

                    }
                    Random rndo1 = new Random();
                    if (rndo1.NextDouble() < 0.09)
                    {
                        ModifyWater(-5);

                    }


                    if (RenderForm.nearbyBush.IsDestroyed)
                    {
                        HideHealthBar();


                        Random rnds = new Random();
                        if (rnds.NextDouble() < 0.4)
                        {
                            AddItem(new InventoryItem
                            {
                                Name = "Stick",
                                Icon = Properties.Resources.Stick,
                                Count = 4,
                                Type = ItemType.Resource
                            });
                        }
                    }
                }

                // Tree
                if (RenderForm.nearbyTree != null)
                {
                    RenderForm.nearbyTree.Mine(this);

                    Random rndo = new Random();
                    if (rndo.NextDouble() < 0.04)
                    {
                        ModifyFood(-5);
 
                    }
                    Random rndo1 = new Random();
                    if (rndo1.NextDouble() < 0.09)
                    {
                        ModifyWater(-5);

                    }
 

                    ShowHealthBar(RenderForm.nearbyTree.Health, RenderForm.nearbyTree.MaxHealth);
                    UpdateHealthBar(RenderForm.nearbyTree.Health, RenderForm.nearbyTree.MaxHealth);

                    if (RenderForm.nearbyTree.IsDestroyed)
                    {
                        HideHealthBar();
            

                        Random rnds = new Random();

                        if (rnds.NextDouble() < 0.6)
                            AddItem(new InventoryItem { Name = "Sap", Icon = Properties.Resources.Tree_Sap_Icon, Count = 1, Type = ItemType.Resource });

                        if (rnds.NextDouble() < 0.01)
                            AddItem(new InventoryItem { Name = "Fairy_Dust", Icon = Properties.Resources.Fairy_Dust_Icon, Count = 1, Type = ItemType.Resource });

                        if (rnds.NextDouble() < 0.009)
                            AddItem(new InventoryItem { Name = "Sprit_Realm_Log", Icon = Properties.Resources.Spirit_realm_Log_Icon, Count = 1, Type = ItemType.Resource });
                    }
                    else
                    {
     
                    }
                }

                // --- Console toggle (F1) ---
                if (e.KeyCode == Keys.F1)
                {
                    panel_Console.Visible = !panel_Console.Visible;

                    if (panel_Console.Visible)
                    {
                        tb_CommandInput.Focus();
                    }
                    else
                    {
                        this.Focus(); // return focus to game
                    }
                }
            }
        }
        #endregion


        #region Add Items at start
        private void SetupExampleItems()
        {
            if (isTesting)
            {
                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.MetalAxe,
                    Name = "Metal_Axe",
                    Count = 1,
                    Type = ItemType.Weapon
                });
                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.MetalAxe,
                    Name = "Metal_Axe",
                    Count = 1,
                    Type = ItemType.Weapon
                });
                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.StoneIcon,
                    Name = "Stone",
                    Count = 12,
                    Type = ItemType.Resource
                });

                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.WorkBenchIcon,
                    Name = "WorkBench",
                    Count = 1,
                    Type = ItemType.Tool
                });

                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.Wood,
                    Name = "Wood",
                    Count = 5,
                    Type = ItemType.Resource
                });

                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.Metal_Ore_Icon,
                    Name = "Metal_Shard",
                    Count = 3,
                    Type = ItemType.Resource
                });

                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.CampFireItem,
                    Name = "Campfire",
                    Count = 1,
                    Type = ItemType.Tool
                });
                AddItem(new InventoryItem
                {
                    Icon = Properties.Resources.CampFireItem,
                    Name = "Campfire",
                    Count = 1,
                    Type = ItemType.Tool
                });

                AddItemToHotbar(new InventoryItem
                {
                    Icon = Properties.Resources.MetalAxe,
                    Name = "Metal_Axe",
                    Count = 1,
                    Type = ItemType.Weapon
                }, 0); // adds Metal Axe to first hotbar slot

                AddItemToHotbar(new InventoryItem
                {
                    Icon = Properties.Resources.Water,
                    Name = "Water_Jar",
                    Count = 1,
                    Type = ItemType.Consumable
                }, 1); // adds Metal Axe to first hotbar slot
            }

            AddItemToHotbar(new InventoryItem
            {
                Icon = Properties.Resources.Painting1,
                Name = "Common_Item_Card",
                Count = 1,
                Type = ItemType.common_painting
            }, 0); // adds Metal Axe to first hotbar slot
        }


        #endregion



        #region Inventory setup and logic
        private void SetupSlots()
        {
            allSlots = new PictureBox[TOTAL_SLOTS];
            allItems = new InventoryItem[TOTAL_SLOTS];

            int slotSize = 60;
            int padding = 10;

            // Hotbar panel (last row)
            p_hotbar = new Panel { BackColor = Color.Transparent, Height = slotSize + 20 };
            this.Controls.Add(p_hotbar);

            // Inventory panel (rows above hotbar)
            p_inventory = new Panel
            {
                BackColor = Color.Transparent,
                Height = (slotSize + padding) * (ROWS - 1) + padding + 20,
                Visible = false // <- only inventory is hidden initially
            };

            this.Controls.Add(p_inventory);

            slotTooltip = new ToolTip();

            for (int r = 0; r < ROWS; r++)
            {
                for (int c = 0; c < COLS; c++)
                {
                    int index = r * COLS + c;

                    PictureBox slot = new PictureBox
                    {
                        Size = new Size(slotSize, slotSize),
                        Location = new Point(padding + c * (slotSize + padding),
                                             padding + (r % (ROWS - 1)) * (slotSize + padding)),
                        BackColor = Color.Yellow,
                        SizeMode = PictureBoxSizeMode.StretchImage,
                        Cursor = Cursors.Hand,
                        Tag = index,
                        Image = emptySlotIcon
                    };
                    slot.MouseEnter += (s, e) =>
                    {
                        int idx = (int)slot.Tag;
                        slot.BackColor = Color.FromArgb(100, 100, 100);

                        if (allItems[idx] != null)
                            slotTooltip.SetToolTip(slot, $"{allItems[idx].Name} x{allItems[idx].Count}");
                    };

                    slot.MouseLeave += (s, e) =>
                    {
                        slot.BackColor = Color.FromArgb(60, 60, 60);
                        // No need to hide the tooltip manually
                    };

                    slot.MouseLeave += (s, e) => slot.BackColor = Color.FromArgb(60, 60, 60);
                    slot.MouseDown += Slot_MouseDown;
                    slot.MouseMove += Slot_MouseMove;
                    slot.MouseUp += Slot_MouseUp;
                    slot.Paint += Slot_Paint;


                    slot.MouseUp += (s, e) =>
                    {
                        if (draggedItem != null) return; // ignore clicks while dragging
                        int idx = (int)slot.Tag;
                        if (e.Button == MouseButtons.Right && allItems[idx] != null)
                        {
                            selectedSlot = idx;
                            slotMenu.Show(System.Windows.Forms.Cursor.Position); // screen coordinates
                        }
                    };
                    allSlots[index] = slot;




                    if (r == ROWS - 1)
                        p_hotbar.Controls.Add(slot); // hotbar row
                    else
                        p_inventory.Controls.Add(slot); // inventory rows
                }
            }
        }

        private void PositionPanels()
        {
            int padding = 10;

            // Hotbar centered at bottom
            p_hotbar.Width = COLS * (60 + padding) + padding;
            p_hotbar.Left = (this.ClientSize.Width - p_hotbar.Width) / 2;
            p_hotbar.Top = this.ClientSize.Height - p_hotbar.Height - 10;

            // Inventory above hotbar
            p_inventory.Width = COLS * (60 + padding) + padding;
            p_inventory.Left = (this.ClientSize.Width - p_inventory.Width) / 2;
            p_inventory.Top = p_hotbar.Top - p_inventory.Height - 10;
        }

        private void SetupTooltipsAndContext()
        {
            slotMenu = new ContextMenuStrip();
            slotMenu.Items.Add("Consume", null, (s, e) => UseItem(selectedSlot));
            slotMenu.Items.Add("Place", null, (s, e) => UseItem(selectedSlot));
            slotMenu.Items.Add("Split", null, (s, e) => SplitItem(selectedSlot));
            slotMenu.Items.Add("Drop", null, (s, e) => DropItem(selectedSlot));

            foreach (var slot in allSlots)
            {
                slot.MouseUp += (s, e) =>
                {
                    int idx = (int)slot.Tag;
                    var item = allItems[idx];

                    if (e.Button == MouseButtons.Right && item != null)
                    {
                        selectedSlot = idx;

                        // Show "Use" only for consumables
                        var useItemMenu = slotMenu.Items[0];
                        useItemMenu.Visible = (item.Type == ItemType.Consumable || item.Type == ItemType.common_painting);

                        var PlaceItemMenu = slotMenu.Items[1];
                        PlaceItemMenu.Visible = (item.Type == ItemType.build);

                        // Optionally you can also disable "Split" for non-stackable items
                        var splitItemMenu = slotMenu.Items[2];
                        splitItemMenu.Visible = (item.Count > 1);

                        slotMenu.Show(System.Windows.Forms.Cursor.Position); // screen coordinates
                    }
                };
            }
        }

        private void SplitItem(int slotIndex)
        {
            var item = allItems[slotIndex];
            if (item == null || item.Count <= 1) return;

            int half = item.Count / 2;

            // Reduce original stack
            item.Count -= half;
            allSlots[slotIndex].Invalidate();

            // Find an empty slot for the new stack
            for (int i = 0; i < allItems.Length; i++)
            {
                if (allItems[i] == null)
                {
                    allItems[i] = new InventoryItem
                    {
                        Name = item.Name,
                        Icon = item.Icon,
                        Count = half,
                        Type = item.Type
                    };
                    allSlots[i].Invalidate();
                    break;
                }
            }
        }

        private void Slot_Paint(object sender, PaintEventArgs e)
        {
            PictureBox slot = sender as PictureBox;
            int index = (int)slot.Tag;

            Image icon = allItems[index]?.Icon ?? emptySlotIcon;
            e.Graphics.DrawImage(icon, new Rectangle(0, 0, slot.Width, slot.Height));

            if (allItems[index] != null && allItems[index].Count > 1)
            {
                using (Brush brush = new SolidBrush(Color.White))
                using (Font font = new Font("Arial", 10, FontStyle.Bold))
                {
                    e.Graphics.DrawString(allItems[index].Count.ToString(), font, brush,
                        new PointF(slot.Width - 18, slot.Height - 18));
                }
            }

            // highlight selected slot in hotbar
            if (index == selectedSlot)
            {
                using (Pen pen = new Pen(Color.Yellow, 3))
                using (GraphicsPath path = RoundedRect(new Rectangle(0, 0, slot.Width, slot.Height), 6))
                {
                    e.Graphics.DrawPath(pen, path);
                }
            }
        }



        // --- Mouse down ---
        private void Slot_MouseDown(object sender, MouseEventArgs e)
        {
            PictureBox slot = sender as PictureBox;
            int index = (int)slot.Tag;
            if (allItems[index] == null) return;

            draggedItem = new PictureBox
            {
                Image = allItems[index].Icon,
                Size = slot.Size,
                SizeMode = PictureBoxSizeMode.StretchImage,
                BackColor = Color.Transparent
            };

            dragInfo = new DragInfo
            {
                Index = index,
                Item = allItems[index],
                Offset = e.Location
            };

            Point mousePos = System.Windows.Forms.Cursor.Position;
            draggedItem.Left = mousePos.X - e.Location.X - dragForm.Left;
            draggedItem.Top = mousePos.Y - e.Location.Y - dragForm.Top;

            dragForm.Controls.Add(draggedItem);
            draggedItem.BringToFront();
        }


        // --- Mouse move ---
        private void Slot_MouseMove(object sender, MouseEventArgs e)
        {
            if (draggedItem == null) return;

            Point mousePos = System.Windows.Forms.Cursor.Position;
            draggedItem.Left = mousePos.X - dragInfo.Offset.X - dragForm.Left;
            draggedItem.Top = mousePos.Y - dragInfo.Offset.Y - dragForm.Top;
        }

        // --- Mouse up ---
        private void Slot_MouseUp(object sender, MouseEventArgs e)
        {
            if (draggedItem == null || dragInfo == null) return;

            int targetIndex = -1;
            Point mousePos = System.Windows.Forms.Cursor.Position;

            // Detect which slot is under cursor
            for (int i = 0; i < TOTAL_SLOTS; i++)
            {
                Rectangle slotRect = allSlots[i].RectangleToScreen(allSlots[i].ClientRectangle);
                if (slotRect.Contains(mousePos))
                {
                    targetIndex = i;
                    break;
                }
            }

            // Swap or stack
            if (targetIndex != -1 && targetIndex != dragInfo.Index)
            {
                SwapOrStack(dragInfo.Index, targetIndex);
            }

            draggedItem.Dispose();
            draggedItem = null;
            dragInfo = null;

            // Redraw inventory
            p_inventory.Invalidate();
            p_hotbar.Invalidate();
        }




        // --- Swap or stack helper ---
        private void SwapOrStack(int fromIndex, int toIndex)
        {
            var dragged = allItems[fromIndex];
            var target = allItems[toIndex];

            if (target != null && dragged.Name == target.Name)
            {
                int total = target.Count + dragged.Count;
                if (total <= MAX_STACK)
                {
                    target.Count = total;
                    allItems[fromIndex] = null;
                }
                else
                {
                    target.Count = MAX_STACK;
                    dragged.Count = total - MAX_STACK;
                    allItems[fromIndex] = dragged;
                }
            }
            else
            {
                allItems[fromIndex] = target;
                allItems[toIndex] = dragged;
            }
        }

        public void SelectSlot(int index)
        {
            if (index < 0 || index >= COLS) return;
            selectedSlot = ROWS * COLS - COLS + index; // bottom row hotbar
            for (int i = 0; i < COLS; i++)
                allSlots[ROWS * COLS - COLS + i].Invalidate();
        }

        private void UseItem(int slotIndex)
        {
            if (slotIndex < 0 || slotIndex >= allItems.Length) return;

            var item = allItems[slotIndex];
            if (item == null) return;

            switch (item.Type)
            {
                case ItemType.Consumable:
                    item.Count--;
                    if (item.Count <= 0)
                        allItems[slotIndex] = null;
                    allSlots[slotIndex].Invalidate();

                    DrinkItem(item);
                    break;

                case ItemType.Weapon:
                    // equip logic
                    break;

                case ItemType.Tool:
                    // use tool logic
                    break;

                case ItemType.Resource:
                    // cannot use
                    break;

                case ItemType.common_painting:
                    // Remove the painting first so AddItem can work properly
                    allItems[slotIndex] = null;
                    allSlots[slotIndex].Invalidate();

                    // Give new items
                    GiveCommonPainting();

                    // Refresh inventory panel so UI updates
                    p_inventory?.Invalidate();
                    break;
            }
        }



        private Random rng = new Random();
        public void GiveCommonPainting()
        {
            var possibleItems = new (string Name, Image Icon, ItemType Type)[]
            {
        ("Wood", Properties.Resources.Wood, ItemType.Resource),
        ("Stone", Properties.Resources.StoneIcon, ItemType.Resource),
        ("Metal_Shard", Properties.Resources.Metal_Ore_Icon, ItemType.Resource),
        ("Water_Jar", Properties.Resources.Water, ItemType.Consumable)
            };

            int itemsToGive = rng.Next(2, 4); // 2 or 3 items
            var shuffled = possibleItems.OrderBy(x => rng.Next()).Take(itemsToGive);

            foreach (var item in shuffled)
            {
                int amount = rng.Next(1, 7); // 1–6 each

                // Each drop gets a new unique UID so it never merges with existing items
                var newItem = new InventoryItem
                {
                    Name = item.Name,
                    Icon = item.Icon,
                    Count = amount,
                    Type = item.Type,
                    UID = Guid.NewGuid()
                };

                AddItem(newItem);
            }
        }


        public void DrinkItem(InventoryItem item)
        {
            if (item == null) return;

            switch (item.Name.ToLower()) // make comparison lowercase
            {
                case "water_jar": // lowercase!
                    DrinkWater(maxWater);
                    break;

                case "raspberry":
                    EatFood(5); 
                    break;

                default:
                    // Other items do nothing
                    break;
            }
        }

        public void DropItem(int slotIndex)
        {
            if (slotIndex < 0 || slotIndex >= TOTAL_SLOTS || allItems[slotIndex] == null) return;
            allItems[slotIndex] = null;
            allSlots[slotIndex].Invalidate();
        }

        public bool AddItem(InventoryItem newItem)
        {
            for (int i = 0; i < allItems.Length; i++)
            {
                var slot = allItems[i];

                // Empty slot: place directly
                if (slot == null)
                {
                    allItems[i] = newItem;
                    allSlots[i].Invalidate();
                    return true;
                }

                // Stackable items (Resources and Consumables only)
                else if (slot.Name == newItem.Name
                         && slot.Type != ItemType.Weapon
                         && slot.Type != ItemType.common_painting
                         && slot.Type == newItem.Type)
                {
                    int remaining = MAX_STACK - slot.Count;
                    if (newItem.Count <= remaining)
                    {
                        slot.Count += newItem.Count;
                        allSlots[i].Invalidate();
                        return true;
                    }
                    else
                    {
                        slot.Count = MAX_STACK;
                        newItem.Count -= remaining;
                    }
                }
            }

            // Could not add all items
            return false;
        }

        private const int HOTBAR_ROW = 4; // last row = h
        private bool AddItemToHotbar(InventoryItem item, int hotbarSlot)
        {
            const int COLS = 8; // number of slots per row
            if (hotbarSlot < 0 || hotbarSlot >= COLS) return false;

            int index = HOTBAR_ROW * COLS + hotbarSlot;

            // For weapons, no stacking
            if (item.Type == ItemType.Weapon)
            {
                allItems[index] = item;
                allSlots[index].Invalidate();
                return true;
            }

            // If stackable (not weapons), try to stack first
            if (allItems[index] != null && allItems[index].Name == item.Name && allItems[index].Type != ItemType.Weapon)
            {
                int total = allItems[index].Count + item.Count;
                if (total <= MAX_STACK)
                {
                    allItems[index].Count = total;
                    allSlots[index].Invalidate();
                    return true;
                }
                else
                {
                    allItems[index].Count = MAX_STACK;
                    item.Count = total - MAX_STACK;
                }
            }

            // Place remaining item in the hotbar slot
            if (allItems[index] == null)
            {
                allItems[index] = item;
                allSlots[index].Invalidate();
                return true;
            }

            return false; // could not add
        }
        private GraphicsPath RoundedRect(Rectangle bounds, int radius)
        {
            int d = radius * 2;
            GraphicsPath path = new GraphicsPath();
            path.AddArc(bounds.X, bounds.Y, d, d, 180, 90);
            path.AddArc(bounds.Right - d, bounds.Y, d, d, 270, 90);
            path.AddArc(bounds.Right - d, bounds.Bottom - d, d, d, 0, 90);
            path.AddArc(bounds.X, bounds.Bottom - d, d, d, 90, 90);
            path.CloseFigure();
            return path;
        }
        #endregion
    }

    public class LootSlot
    {
        public PictureBox IconBox;
        public Label CountLabel;
        public InventoryItem Item;
    }

    public enum ItemType
    {
        build,
        Consumable,
        Weapon,
        Tool,
        Resource,
        common_painting,

    }

    public class InventoryItem
    {
        public Image Icon { get; set; }
        public string Name { get; set; }
        public int Count { get; set; }
        public ItemType Type { get; set; }

        public Guid UID { get; set; } = Guid.NewGuid(); // unique per pickup
    }

}
Editor is loading...
Leave a Comment