Untitled
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