iwalidza Posted March 20, 2020 Share Posted March 20, 2020 How i can make a inventory system !:) Link to comment
The_GTA Posted March 20, 2020 Share Posted March 20, 2020 (edited) Hello iwalidza, since you do not provide any design wishes and I have no experience with inventory system design, I will limit my contribution to the technical side of inventory systems. You may want to create new kinds of items for roleplay such as keys or identity certificates that players have to collect and treasure. An inventory system is defined as a set of items that belong to peds or players. Items can be taken out or put in at wish. Thus we want to attach a table of items for at least each player on the server and synchronize the items with the clients. server.Lua -- We want to create items definitions here. local item_definitions = {}; local function register_item(id, name, description) local def = { ["name"] = name, ["id"] = id, ["description"] = description }; item_definitions[id] = def; end register_item(1, "Knife", "Sharp item to cut things"); register_item(2, "Sword", "Sharp weapon for slashing"); register_item(3, "Key", "Used to access secret areas in the game"); -- Item local player_inventories = {}; addEventHandler("onPlayerQuit", root, function() player_inventories[source] = nil; end ); local function find_existing_player_inv_slot(inv_items, item_id) for m,n in ipairs(inv_items) do if (n.item_id == item_id) then return n; end end return false; end local function give_item_to_player(player, item_id, count) local inv = player_inventories[player]; local item_carry = find_existing_player_inv_slot(inv, item_id); if (item_carry) then item_carry.count = item_carry.count + count; return true; end local new_carry = { ["item_id"] = item_id, ["count"] = count }; table.insert(inv, new_carry); return true; end addEventHandler("onPlayerJoin", root, function() local inventory = {}; player_inventories[source] = {}; give_item_to_player(source, 1, 1); give_item_to_player(source, 2, 1); give_item_to_player(source, 3, 1); end ); (code has not been tested) This is a sample system I just created. There is a knife, sword and key. At join time each player does receive a copy of any item. Now imagine that you have a marker that you can only enter with a key. server.Lua local function does_player_have_item(player, item_id) local inventory = player_inventories[player]; local slot = find_existing_player_inv_slot(inventory, item_id); if (slot) and (slot.count > 0) then return true; end return false; end local function remove_player_item(player, item_id, count) local inventory = player_inventories[player]; for m,n in ipairs(inventories) do if (n.item_id == item_id) and (n.count > 0) then local can_remove = math.min(count, n.count); n.count = n.count - can_remove; count = count - can_remove; if (count == 0) then break; end end end end local marker = createMarker(0, 0, 3, "cylinder"); addEventHandler("onMarkerHit", marker, function(hitElement) if not (getElementType(hitElement) == "player") then return; end; if not (does_player_have_item(hitElement, 3)) then outputChatBox("You cannot enter this zone because you have no key."); return; end outputChatBox("Using key to enter the zone."); remove_player_item(hitElement, 3, 1); end ); This script creates a marker in the middle of the map. If you hit the marker then you use a key. Once you have used your starting key then you cannot successfully hit the marker anymore. The message should change the second time you hit the marker. The marker does only work with players. I hope I could help you with this Edited January 26, 2022 by The_GTA 1 Link to comment
iwalidza Posted March 20, 2020 Author Share Posted March 20, 2020 Thanks, thanks and thanks again @The_GTA ,For this And if you can help me with the organizing system inside gui or dx it would be good to get an idea about it Link to comment
The_GTA Posted March 20, 2020 Share Posted March 20, 2020 (edited) 52 minutes ago, iwalidza said: Thanks, thanks and thanks again @The_GTA ,For this And if you can help me with the organizing system inside gui or dx it would be good to get an idea about it Glad to be of help. Since you are asking so kindly I want to give you ideas how to continue with your inventory system. I absolutely recommend going with dx because it is more powerful than CEGUI. So these are the functions that should be used: dxDrawImage - drawing inventory icons as well as general GUI images dxDrawText - displaying the item names and descriptions as well as GUI text dxDrawRectangle - styling of the inventory window/grid/whatever bindKey function - opening the inventory with a button onClientRender event - drawing the dx UI each frame onClientClick event - clicking on items in inventory for selection and action onClientMouseMove event - hovering over items to display the description, highlighting, etc triggerServeEvent - asking the server to use an item or update the inventory in some way (throw away item, reordering the inventory, etc) triggerClientEvent - transmitting the inventory to the client Here is how I imagine an inventory to look. Code on requesting the inventory from the server: server.Lua addEvent("onRequestInventory", true); addEventHandler("onRequestInventory", root, function() triggerClientEvent(client, "onClientReceiveInventory", root, player_inventories[client], item_definitions); end ); client.Lua addEvent("onClientReceiveInventory", true); addEventHandler("onClientReceiveInventory", root, function(player_inventory, item_definitions) -- TODO: use the data somehow. end ); local function send_inventory_request() triggerServerEvent("onRequestInventory", root); end Feel free to ask more questions when you have some code done already Edited March 20, 2020 by The_GTA 2 1 Link to comment
iwalidza Posted March 20, 2020 Author Share Posted March 20, 2020 @The_GTA Thank you again, you make me happy 1 Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 function Inventory:takeItem(itemID,count,slot) if not itemID then return false end self.infos = { getItemInfos (itemID)} if not count then count = self.infos[2] end if not slot then for i = #self.items ,1 ,-1 do if self.items[i][1] == itemID then local canTake = math.min(count,self.items[i][2]) self.items[i][2] = self.items[i][2] - canTake if self.items[i][2] == 0 then table.remove(self.items,i) end break end end end end I want take 140 from the item and I have 3 of this item 124 124 100 I want take 100 from the last item and second item take just 40 how can do it @The_GTA Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 Hello iwalidza, let me ask you some questions about your code first: if not count then count = self.infos[2] end Is this supposed to set "count" to the maximum value of currently held items? This would not make sense in your model because you have multiple slots with varying count of items between each slot. self.infos = { getItemInfos (itemID)} What does the getItemInfos function do? Could you post the definition aswell? Now let's get to the ideas. Let's assume you have slots 1, 2, 3, where slot 1 is itemID 124, slot 2 is itemID 124 and slot 3 is itemID 140. I don't understand which item you want to pick from? Slot 1, 2 or 3? Let's assume you pick from slot 1 with count = 140. inv:takeItem(inv:getItemIDFromSlot(1), 140, 1) inv:takeItem(inv:getItemIDFromSlot(2), 40, 2) inv:takeItem(inv:getItemIDFromSlot(3), 100, 3) Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 @The_GTA items = { [1] = {name = "Appel",stack = "10",isDurability = false,isAmmo=false}; [2] = {name = "Building Plan",stack = "1",isDurability = false,isAmmo=false}; [3] = {name = "Assault Rifle",stack = "1",isDurability = true,isAmmo=true}; [4] = {name = "5.56 Rifle ammo",stack = "128",isDurability = false,isAmmo=false}; [5] = {name = "Longsleeve T-Shirt",stack = "1",isDurability = false,isAmmo=false}; [6] = {name = "T-Shirt",stack = "1",isDurability = false,isAmmo=false}; [7] = {name = "Boots",stack = "1",isDurability = false,isAmmo=false}; [8] = {name = "Improvised Balaclava",stack = "1",isDurability = false,isAmmo=false}; [9] = {name = "Heavy Plate Jacket",stack = "1",isDurability = false,isAmmo=false}; [10] = {name = "Pants",stack = "1",isDurability = false,isAmmo=false}; [11] = {name = "Coffee Can Helmet",stack = "1",isDurability = false,isAmmo=false}; [12] = {name = "Revolver",stack = "1",isDurability = true,isAmmo=true}; [13] = {name = "Pistol Bullet",stack = "128",isDurability = false,isAmmo=false}; [14] = {name = "Hammer",stack = "1",isDurability = false,isAmmo=false}; [15] = {name = "Pickaxe",stack = "1",isDurability = true,isAmmo=false}; [16] = {name = "Hatchet",stack = "1",isDurability = true,isAmmo=false}; } function getItemInfos (id) return items[id].name,items[id].stack,items[id].isDurability,items[id].isAmmo end that about getItemInfos and take item firts arg its about item id in items ids i use it to select item waht i need if not count then count = self.infos[2] end and that if i want to take stack just i don't add count Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 1 minute ago, iwalidza said: @The_GTA items = { [1] = {name = "Appel",stack = "10",isDurability = false,isAmmo=false}; [2] = {name = "Building Plan",stack = "1",isDurability = false,isAmmo=false}; [3] = {name = "Assault Rifle",stack = "1",isDurability = true,isAmmo=true}; [4] = {name = "5.56 Rifle ammo",stack = "128",isDurability = false,isAmmo=false}; [5] = {name = "Longsleeve T-Shirt",stack = "1",isDurability = false,isAmmo=false}; [6] = {name = "T-Shirt",stack = "1",isDurability = false,isAmmo=false}; [7] = {name = "Boots",stack = "1",isDurability = false,isAmmo=false}; [8] = {name = "Improvised Balaclava",stack = "1",isDurability = false,isAmmo=false}; [9] = {name = "Heavy Plate Jacket",stack = "1",isDurability = false,isAmmo=false}; [10] = {name = "Pants",stack = "1",isDurability = false,isAmmo=false}; [11] = {name = "Coffee Can Helmet",stack = "1",isDurability = false,isAmmo=false}; [12] = {name = "Revolver",stack = "1",isDurability = true,isAmmo=true}; [13] = {name = "Pistol Bullet",stack = "128",isDurability = false,isAmmo=false}; [14] = {name = "Hammer",stack = "1",isDurability = false,isAmmo=false}; [15] = {name = "Pickaxe",stack = "1",isDurability = true,isAmmo=false}; [16] = {name = "Hatchet",stack = "1",isDurability = true,isAmmo=false}; } function getItemInfos (id) return items[id].name,items[id].stack,items[id].isDurability,items[id].isAmmo end You should either turn the "stack" key in the tables inside of the "item" table to Lua numbers or use tonumber inside of the getItemInfos function, for example... items = { [1] = {name = "Appel",stack = 10,isDurability = false,isAmmo=false}; (...) } This is important because you are using numeric operations in your Inventory:takeItem method. Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 done. what about take item ? Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 (...) if not slot then for i = #self.items ,1 ,-1 do if self.items[i][1] == itemID then slot = i break end end if not slot then return false end end local canTake = math.min(count,self.items[slot][2]) self.items[slot][2] = self.items[slot][2] - canTake if self.items[slot][2] == 0 then table.remove(self.items,slot) end (...) Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 @The_GTA playerInventroy:takeItem(4,140) that just take 100 from items Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 2 minutes ago, iwalidza said: @The_GTA playerInventroy:takeItem(4,140) that just take 100 from items According to your stack definition you can only have 128 on each stack. I recommend you to change your algorithm to take items from multiple stacks until the requested take-count is exhausted. Are you familiar with this idea? Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 if i set count like 140 i want first take 100 and take 40 from 128 1 minute ago, The_GTA said: According to your stack definition you can only have 128 on each stack. I recommend you to change your algorithm to take items from multiple stacks until the requested take-count is exhausted. Are you familiar with this idea? Example please. @The_GTA Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 local slot = #self.items while (count > 0) and (slot > 0) do if self.items[slot][1] == itemID then local canTake = math.min(count,self.items[slot][2]) self.items[slot][2] = self.items[slot][2] - canTake if self.items[slot][2] == 0 then table.remove(self.items,slot) end count = count - canTake end slot = slot - 1 end if (count > 0) then outputDebugString("not taken entire count"); end slot parameter to Inventory:takeItem has been neglected. Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 12 minutes ago, The_GTA said: local slot = #self.items while (count > 0) and (slot > 0) do if self.items[slot][1] == itemID then local canTake = math.min(count,self.items[slot][2]) self.items[slot][2] = self.items[slot][2] - canTake if self.items[slot][2] == 0 then table.remove(self.items,slot) end count = count - canTake end slot = slot - 1 end if (count > 0) then outputDebugString("not taken entire count"); end slot parameter to Inventory:takeItem has been neglected. thank you. Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 1 minute ago, iwalidza said: thank you. You're welcome! I believe this algorithm is important to a lot of inventory systems that are slot based. Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 1 hour ago, The_GTA said: You're welcome! I believe this algorithm is important to a lot of inventory systems that are slot based. what the best idea to get slot from mouse click? Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 3 minutes ago, iwalidza said: what the best idea to get slot from mouse click? Calculate the rectangles of each slot in the mouse click handler and associate the rectangle with the slot data structures. Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 1 minute ago, The_GTA said: Calculate the rectangles of each slot in the mouse click handler and associate the rectangle with the slot data structures. i have the problem with calculate function Inventory:getSlot (x,y) for i = 1, self.slots do local t = i - 1 local xOffset = self.startX + (t*(self.iconSize + self.padding)) local yOffset = self.startY + (math.floor(t/6)*(self.iconSize + self.padding)) xOffset = xOffset - math.floor(t/6)*(6*(self.iconSize + self.padding)) if isInBox(x,y,xOffset,xOffset + self.iconSize,yOffset,yOffset + self.iconSize) then slot = i return slot end end end its return " " " " "slotid" Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 (edited) function Inventory:getSlot (x,y) for i = 1, #self.slots do -- table local t = i - 1 local xOffset = self.startX + (t*(self.iconSize + self.padding)) local yOffset = self.startY + (math.floor(t/6)*(self.iconSize + self.padding)) xOffset = xOffset - math.floor(t/6)*(6*(self.iconSize + self.padding)) if isInBox(x,y,xOffset,xOffset + self.iconSize,yOffset,yOffset + self.iconSize) then return i end end return false -- good idea end What is the definition of the isInBox function? Edited January 27, 2022 by The_GTA Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 its work good but with down one just return false beltInventory not work why? playerInventroy = Inventory:new('player',24,((screen.x / 2) - ((DEFAULT_iconSize - DEFAULT_padding) * 3)),screen.y - ((DEFAULT_iconSize + (DEFAULT_padding * 2)) * 5),nil,nil,false) clothInventory = Inventory:new('cloth',6,(0 + (DEFAULT_padding * 13)) ,screen.y - ((DEFAULT_iconSize + DEFAULT_padding) * 3.37),nil,nil,false) beltInventory = Inventory:new('belt',6,((screen.x / 2) - ((DEFAULT_iconSize - DEFAULT_padding) * 3)),screen.y - (DEFAULT_iconSize + DEFAULT_padding),nil,nil,true) function Inventory:getSlot (x,y) print(self.type) for i = 1, self.slots do local t = i - 1 local xOffset = self.startX + (t*(self.iconSize + self.padding)) local yOffset = self.startY + (math.floor(t/6)*(self.iconSize + self.padding)) xOffset = xOffset - math.floor(t/6)*(6*(self.iconSize + self.padding)) if isInBox(x,y,xOffset,xOffset + self.iconSize,yOffset,yOffset + self.iconSize) then return i end end return false end its return just cloth and player why? @The_GTAi fix it and how i can get the inventory player click like if click in playerInventory its return playerInventory or clothInventory Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 9 minutes ago, iwalidza said: and how i can get the inventory player click Put all inventories into a list, iterate over them in the mouse click handler and check which one has a defined rectangle item slot at the current mouse position. Store the successful inventory in a variable and retrieve it's type field to check which one it is. Link to comment
iwalidza Posted January 27, 2022 Author Share Posted January 27, 2022 58 minutes ago, The_GTA said: Put all inventories into a list, iterate over them in the mouse click handler and check which one has a defined rectangle item slot at the current mouse position. Store the successful inventory in a variable and retrieve it's type field to check which one it is. how i can chack if player mouse still click Link to comment
The_GTA Posted January 27, 2022 Share Posted January 27, 2022 Just now, iwalidza said: how i can chack if player mouse still click What do you mean? If you execute the on click handler then a click has happened. Please rephrase your question or show details. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now