Dropping items from inventory+Access var from other program?

Posted By: Ruben

Dropping items from inventory+Access var from other program? - 12/26/13 06:30

Is there a way that I can access a variable value in one program from a second different program?

For example, lets say I have two different programs: mainProgram.c and inventory.c . If the mainProgram.c program file needs to determine what a value is for a variable saved in a different program file, like inventory.c , in order to execute some process in mainProgram.c , how would I call on that inventory.c variable in the gameProgram.c ?

So, if the value in inventory.c that gameProgram.c needs is saved in a variable called "slot_id", and the "slot_id" variable is stored in a function inside of inventory.c , how would I call on the value stored in slot_id from the main function in gameProgram.c ?

For example, here is the logic:

gameProgram.c : I need the value of the variable "slot_id" , that is stored in inventory.c , in order to initiate an action.

inventory.c : passes value of "slot_id" back to gameProgram.c .

gameProgram.c : Takes "slot_id" value passed from inventory.c , and depending on its value, takes a certain action.

**************

Does anyone know how I can call on the "slot_id" variable stored in the inventory.c program, using the gameProgram.c program, to make this happen?

Here is the actual code in inventory.c that has "slot_id" stored in it:

Code:
/*
Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image
*/

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

Posted By: rayp

Re: Access variable from other program? - 12/26/13 08:29

How many threads about inventory.c have u planned ? Just wondering...
Posted By: Feindbild

Re: Access variable from other program? - 12/26/13 11:38

Why are those two scripts running as separate threads?
Posted By: Ruben

Re: Access variable from other program? - 12/27/13 05:29

Basically, this is what I am trying to do. I am trying to create an inventory bag for my player, so that my player can store items, and use them. Inventory.c is a public domain program coded by somebody else to help me do this.

I can create multiple slots in my inventory bag to put items into. However, I am trying to make one special slot in the inventory bag that only accepts weapon items. Also, if you click and drag a certain weapon image into this special slot, it would arm the player with the weapon that is placed into this slot. So if a picture of a sword is in this special slot, then the player will be holding a sword in her/his hand. If a picture of a mace is in this special slot, then the player will be holding a mace in her his hand. If there is no image placed into this special slot, then the player is not armed with anything, etc.

This is the code in the main function of my main program (separate from inventory.c ) to try and make this happen:

Code:
// OrcStronghold.c Program

...

function active_weapon_slot()
{
   if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx")) 
   {
      active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
   }
   else
   {
      ent_remove(active_sword);
   }
}

...

function main()
{	
   ...

   item_shield = inv_create_item(1,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(1,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(0,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(0,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(1,0,"gold_coins.pcx","gold_coins.pcx");
   bag = inv_create_bag(1,"leather_seam.pcx");  // <---- added this line
   
   // ACTIVE ITEM SLOT
   
   active_weapon_slot = inv_add_slot_to_bag(bag, 0, 1, "leather_texture.pcx", 
      9, 60); // 3rd value (group_id) = 1.  Only equipment items with group_id 
              // = 1 can be placed into this slot.

   // EACH ROW OF INVENTORY BAG IS SPACED OUT BY 64 HEIGHT
   // FIRST ROW OF INVENTORY BAG

   inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
   inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);
   inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
   inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
	
   // SECOND ROW OF INVENTORY BAG
	
   inv_add_slot_to_bag(bag,5,0,"leather_texture.pcx",9,214);
   inv_add_slot_to_bag(bag,6,0,"leather_texture.pcx",70,214);
   inv_add_slot_to_bag(bag,7,0,"leather_texture.pcx",130,214);
   inv_add_slot_to_bag(bag,8,0,"leather_texture.pcx",190,214);
	
   // THIRD ROW OF INVENTORY BAG
	
   inv_add_slot_to_bag(bag,9,0,"leather_texture.pcx",9,278);
   inv_add_slot_to_bag(bag,10,0,"leather_texture.pcx",70,278);
   inv_add_slot_to_bag(bag,11,0,"leather_texture.pcx",130,278);
   inv_add_slot_to_bag(bag,12,0,"leather_texture.pcx",190,278);
	
   ...  
}


Code:
// Inventory.c program

...

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
   // Create item and assign images
	
   Item* item = new(Item);
   item->floating_icon = floating_icon;		
   item->inventory_icon = inventory_icon;
   item->id = item_id;
   item->group_id = group_id;
	
   // Add item to global array for cleanup purposes

   inv_items_array[inv_item_count] = item;
   inv_item_count++;
	
   return item;		
}

...

function inv_create_bag(int bag_id, STRING* image_name)
{
   Bag* bag;
   bag = new(Bag);
	
   bag->image_name = image_name;
   bag->id = bag_id;
	
   // Initialize slot_count to 0
   bag->_slot_count = 0;
   bag->is_open = 0;
	
   // Add bag to global array for cleanup purposes

   inv_bags_array[inv_bag_count] = bag;
   inv_bag_count++;
	
   return bag;
}

...

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
  Slot* new_slot;
  new_slot = new(Slot);

  // Set the position for the new slot
	
  new_slot->rel_x_pos = rel_x_pos;
  new_slot->rel_y_pos = rel_y_pos;	
  new_slot->background_image = default_image;
  new_slot->item = NULL;
  new_slot->id = slot_id;
  new_slot->group_id = group_id;
  new_slot->bag_id = bag->id;	
		
  bag->slots[bag->_slot_count] = new_slot;
	
  bag->_slot_count += 1;	
}

...



So, the variable "floating_icon" is saved in the "inv_create_item" function inside the inventory.c program. When I use the inv_create_item in the "function main" inside the OrcStronghold.c program, in order to create a new item that can be placed inside the inventory bag, I am setting a string value to the third value in the inv_create_item function, which belongs to the "floating_icon" variable.

I try to set the "active weapon" slot instance of inv_create_item equal to a variable called "active_weapon_slot", and this is done in the "function main", inside the OrcStronghold.c program.

I then create a separate function from the "function main" inside the OrcStronghold.c program called "active_weapon_slot" function. In this function, I try to compare the floating_point string value in the "active weapon" slot to whether it equals "steel_sword.pcx". If it does, then I try to create a sword entity to be placed in the player's hand using the ent_create function, and an attach_weapon function that snaps the weapon (saved into its own separate .mdl file from the player) into the player's hand.

When I try and compile the OrcStronghold.c program, I get this error:

Compiling ORCSTRONGHOLD.C - [Esc] to abort..........
Error in 'line 179:
'floating_icon': is not a member of 'BOOL'
< if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx"))
..0.129 sec
Error compiling ORCSTRONGHOLD.C
Error E355: Startup failure - any key to abort

***********************

How can I take the floating_icon string value that is passed to the "inv_create_item" function, and compare it to the string value "steel_sword.pcx" (which is the name of the image being placed in the "active weapon" slot; and if they are equal, arming the player with a sword. If they are not equal (meaning the string value in the floating_icon variable is not equal to the string "steel_sword.pcx", then a sword will not be armed in the hand of the player. How can I access that floating_icon value, that is stored in the inv_create_item function in inventory.c ?

P.S. Is this issue beyond the "Gamestudio Basics" forum? Should I post this in a more advanced thread?
Posted By: CanadianDavid

Re: Access variable from other program? - 12/28/13 01:56

Sorry without reading your entire article, one way to share values between programs is to use file input/output; for example, writing and reading values from a common text file. Another way would be to use something like popen() in C to pipe or send commands to another program. I'm assuming by "program," you mean compiled executables otherwise if you meant between scripts you could just use global variables or, in Gamestudio, skills. Sorry if I completely missed your question.
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 07:12

I will try and explain it as simply as I can. I have probably used too many words.

Lets say I have a program called Program1.c . In this program, I have a main function.

Now lets say I can a second program called Program2.c . On the top of Program1.c , I have this code:

#include "Program2.c"

I have #included Program2.c to be used by Program1.c , because Program2.c has functions in it that need to be called on by Program1.c in order to initiate certain actions.

Lets say that there is a function inside Program2.c called print_text() that accepts a string to a variable called "string_output": print_text(String string_output) . Suppose that this variable "string_output" is not declared as a variable in Program1.c , even though Program1.c needs to access this value from Program2.c .

Lets also say that Program1.c passes strings as needed to print_text() (which is stored in Program2.c) in order to output text on the screen. So if Program1.c passes the string "strawberry" to print_text():

Example:
Code:
print_text("strawberry");



...then the word "strawberry" will be displayed on the screen.

Now lets go a step further. Suppose that Program1.c wants to be able to attach a sword (.mdl sword model) to the player's hand to wield as a weapon, only if Program1.c passes the string "sword" to print_text(). Example:

print_text("sword");

In order to accomplish this, Program1.c holds a function called string_compare() that tries to compare the value of the string variable "string_output" currently saved in the print_text() function stored in Program2.c , to the string "sword". If the string value of string_output equals "sword", then a .mdl sword model will be attached to the player's hand. If they are not equal, then the .mdl sword model will not be attached to the player's hand:

Example:
Code:
// Stored in Program1.c

function string_compare()
{
   if(str_cmp(string_output, "sword")) // string_output is stored in 
                                       //    print_text() in Program2.c .
                                       //    How can Program1.c access the
                                       //    string_output string value in
                                       //    print_text() function, Program2.c ?
   {
      ent_create ("sword.mdl", my.x, attach_weapon); // Attaches a .mdl sword
                                                     //    to player's hand.
   }
}



How can Program1.c access the string value of "string_output" stored in Program2.c? As of now, I have this logic in my program, but I am getting an error on string_output variable in the string_compare function inside of Program1.c .
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 07:33

Originally Posted By: Feindbild
Why are those two scripts running as separate threads?

If what you mean by separate threads is that they are in separate programs, the value that I am trying to access is stored inside a function that is stored inside a program called inventory.c , more specifically I am trying to access the "floating_icon" value in the function "inv_create_item()" function inside inventory.c , from another .c program called OrcStronghold.c . I did put this code at the top of OrcStronghold.c :

#include "inventory.c"

Here is the open source inventory.c code:

Code:
// 
// Inventory.c - programmed by Bret Truchan.  You are welcome to use this inventory
// system in the creation of commercial or free games.  You may not use it for any
// other purpose.
// 

/*


DOCUMENTATION

Table of Contents

   I. Introduction
  II. Essentials: inv_init() and inv_cleanup()
 III. Creating items for your inventory
  IV. Making your first bag
   V. Opening and Closing bags
  VI. Setting bag close and drag regions
 VII. Adding items to bags

VIII. Item Groups
  IX. Callbacks
  X. Other helpful functions


I. Introduction
---------------

Hello fellow programmer!  I hope that you can find the following inventory
system useful.  My main goal when making this inventory system was to decouple
the inventory system from the rest of the game code.  I also wanted to make it
as easy as possible to create and manage your inventory system.

This inventory has the following features:

1. Easy to use
2. Supports multiple bags
3. Handles the layering of bags for you
4. Supports callbacks for inventory events
5. Supports item "groups". (For example, gerbils can only be put in gerbil
slots.)

I modeled the inventory system after World of Warcraft.  One limitation to this
system is that slots in bags really need to be the same size.  I know how to 
fix this so, for example, your sword would show up huge in the sword slot but
small in a backpack slot, but I'll have to save that for a later release.



II. Essentials: inv_init() and inv_cleanup()
--------------------------------------------

Let's dive right in.  Creating your inventory is done in your lite-c code. 
You should not need to modify inventory.c.  Before anything else, include
inventory.c in your code, like so:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c" // <---- ADDED THIS

 void main()
 {
   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   // etc..

Add the inv_init(); function call to your main loop as shown above.  Because
inventory.c uses some low level C structures, you need to call inv_cleanup()
just before your game closes.


III. Creating items for your inventory
--------------------------------------

Let's skip ahead and create some images that will be needed for your
inventory.  If you have the demo for this inventory code, you can use my demo
images.

  pack.pcx - The is the background image of your inventory pack.
  slot_bg.pcx - The background image of an empty slot.
  item1.pcx - An icon of an item, such as a sword.  This should be the same
size as slot_bg.pcx.

Ok, back to items....

Items are strange.  You might think of an item like a "sword" or "gun". 
However, this inventory system is NOT trying to control how you manage items
for your game.  Although you might have a "sword" item in your inventory, the
structure that's passed around in the inventory code should NOT have
attributes such as "damage" or "weight".

Let's move ahead with an example of adding your first item - A pile of sand.
Maybe this pile of sand will go into your nephew's Christmas Stocking
because he ate all your friggin' cookies?!

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");


See that inv_create_item(...) statement?  inv_create_item() creates an abstract
item in your inventory system. Let's break it down:

 item_pointer = inv_create_item(item_id,group_id,floating_icon,inventory_icon);

Arguments:

 item_id - You make this up.  It can be anything that you want.  It doesn't affect the inventory engine.
 
 group_id - Later on, slots will also have a group id.  Items can only be put into slots with the right group id.

 floating_icon - The image used for the item while it's being dragged around the inventory system.

 inventory_icon - The image for displaying the item when the item is in a slot.

To reiterate, we introduced a new item into our inventory system.  We gave it an item id of 1, which really doesn't mean anything.  We gave it a group_id = 0, which means that the item can be placed into any slot having group_id=0.  We choose the same image "item1.pcx" for the icon used to "float" the item around in the inventory as well as the icon that represents the item in a slot.  That's good enough for now.  We'll keep moving forward..


IV. Making your first bag
-------------------------

There are a few terms that I loosly introduced above.  Your inventory may have multiple "bags".  Bags have multiple "slots", and slots may contain items.  Let's make our first bag.  Luckily, it's pretty easy:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;
 Bag* bag; // <---- added this line

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");
   bag = inv_create_bag(1,"pack.pcx");  // <---- added this line


Easy!  When you do this, the bag does not appear on the screen.  We'll handle that later.  For now, let's look closely at the
inv_create_bag() function:

   bag = inv_create_bag(bag_id,bag_image);

Arguments

 bag_id - You make this up.  It's not used within the inventory system, but it can be useful when handling callbacks.  We'll  
 discuss callbacks later on.

 bag_image - This should be an image of your open inventory bag.


Creating a bag is only half the battle.  Generally, you use the inv_add_slot_to_bag() function to add
a slot to your bag.  Here's the generic version:

  function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)

Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image

Here's a real world example of creating 4 slots to your bag:

  inv_add_slot_to_bag(bag,1,0,"slot_bg.pcx",9,38);
  inv_add_slot_to_bag(bag,2,0,"slot_bg.pcx",44,38);
  inv_add_slot_to_bag(bag,3,0,"slot_bg.pcx",78,38);
  inv_add_slot_to_bag(bag,4,0,"slot_bg.pcx",112,38);


V. Opening and Closing bags
---------------------------

Opening bags is easy:

  inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position);

That's it!  Here's use a real world example:

  inv_open_bag(bag, 100,100);

Closing your bag is even easier:

  inv_close_bag(bag);

We haven't added items to bags yet, but you'll see that it's very easy. When you open and close bags, the bags remember what items they contained.  You don't need to re-add the items.


VI. Setting bag close and drag regions
--------------------------------------

This inventory system allows you to drag bags around the screen and close them.  It's optional.  All you need to do is tell the inventory system where the drag region and close region are on the bag image.  Here's an example:

  inv_set_bag_drag_region(bag,5,3,128,18);
  inv_set_bag_close_region(bag,129,0,148,19);

The arguments are:

 function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
 function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)

Quick note:  For multiple bags, the inventory code automatically handles which bag should be "on top" if they overlap.


VII. Adding items to bags
-------------------------

Believe it or not, you're almost done.  Adding items to the inventory system can be done in two ways.  First, you can add an item directly to a bag.  Alternatively, you can create an item and immediately have it "float" (which means that the icon is visible and is being dragged by the mouse).

Adding an item directly to a bag:

  function inv_insert_item_into_bag(Bag* bag, Item* item)

For example:

  inv_insert_item_into_bag(bag,item_sand);

  (This function will return 1 if there was room in the bag for the item, otherwise 0.)

... OR "Floating" a new item:

  function inv_float_item(Item* item)

For example:

  function inv_float_item(item_sand);

That's it!


VIII. Item Groups
-----------------

Item groups are super easy.  Group_id 0 is special.  If you assign group_id = 0 to a slot, that slot can hold ANY
item.  Let's pretend that you want to make a weapon slot that can ONLY hold weapons.  When you create the sword item,
use the group_id = 4;  Then, when you create the sword slot, set its group_id = 4 too.  Done!


IX. Callbacks
-------------

If you need to know when certain events happen in the inventory system, you'll want to use the callbacks.  I'll explain with an example.  Let's say that you want to know whenever a bag is opened.  First, you need to define a function in your lite-c that will be called when a bag is open.  An open-bag callback function looks like:

a) open_bag_callback

  // put something like this in your lite-c

  function bag_was_opened(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_open_bag_callback() like so:

  set_on_open_bag_callback("bag_was_opened");

Whenever a bag is opened, your function bag_was_opened() will be called.  The bag_id of the opened bag will be passed into your function automatically.  Remember when we first created a bag and I said that the bag_id was useless?  I lied.  Here's where it comes into play.  You can tell which bag was opened by looking at the bag_id that's passed in to your callback function.

b) on_click_callback

This is most complicated callback.  It's triggered whenever someone clicks on a slot.  To use it, add something like this to your lite-c:

  function slot_was_clicked(int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id)
  {
    if (action == INV_ITEM_PLACED)
    {
       // item was placed in bag
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot  
       // removed_item_id is 0 and should be ignored
    }
    if (action == INV_ITEM_REMOVED)
    {
       // item was removed from bag  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is 0 and should be ignored 
       // removed_item_id is the item id that was removed from the slot
    }
    if (action == INV_ITEM_SWAPED)
    {
       // item was put in to a slot that already contained an item, so they were swapped  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot 
       // removed_item_id is the item id that was removed from the slot
    }
  }

And register your callback like:

  set_on_click_callback("slot_was_clicked");


c) on_bag_close_callback

This is just like on_bag_open_callback.  Here's an example:

  function bag_was_closed(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_close_bag_callback() like so:

  set_on_close_bag_callback("bag_was_closed");



X. Other helpful functions
--------------------------

 PANEL* inv_get_bag_panel_ptr(Bag* bag); // given a bag, return its panel pointer
 inv_is_bag_open(Bag* bag); // returns 1 if the bag is open, otherwise 0
 inv_get_open_bag_count(); // returns the number of open bags
 inv_is_floating(); // returns 1 if the player is floating an inventory item
 inv_is_item_in_bag(Bag* bag, Item* item); // returns 1 if the item is in the bag


*/





// ============================ BEGIN CODE =================================


#define new(type) malloc(sizeof(type##))
#define delete(object) free(object)

#define bag_layer 1
#define slot_layer 2
#define floating_item_layer 94

#define INV_ITEM_PLACED 1
#define INV_ITEM_SWAPPED 2
#define INV_ITEM_REMOVED 3

/* 
	struct Item

	The item structure holds a single item's information.  Items are intended to 
	track inventory icons only.  They're not really meant to manage an entire
	game's items.  For example, you would NOT use the item struct to hold values
	such as damage or defense rating for a sword.  The id in the item struct is
	intended to help associate these inventory based items with whatever item
	management is used in the game.  The id is set by the game developer to
	any arbitrary value.  The id is used in callback functions.
	
*/

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
	PANEL* slot_panel;
	
	int id;
	int group_id;
	int rel_x_pos;
	int rel_y_pos;
	int width;
	int height;
	
	STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
	int id;
	int is_open;
	
	int drag_region_top_left_x;
	int drag_region_top_left_y;
	int drag_region_bottom_right_x;
	int drag_region_bottom_right_y;

	int close_region_top_left_x;
	int close_region_top_left_y;
	int close_region_bottom_right_x;
	int close_region_bottom_right_y;
	
	PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;
     
} Bag;


// === Floating Item ===

typedef struct
{
	Item* item;
	PANEL* floating_item_panel;
	
} FloatingItem;


// Ugly linked list for keeping track of panels and associated slots

typedef struct SlotPanelAssoc
{
	PANEL* slot_panel;
	Slot* slot;
	struct SlotPanelAssoc* next;
	struct SlotPanelAssoc* prev;
	
} SlotPanelAssoc;


// Another ugly linked list for keeping track of z-order of open bags

typedef struct BagLayer
{
	Bag* bag;
	struct BagLayer* next;
	struct BagLayer* prev;
	
} BagLayer;


// Global variables

SlotPanelAssoc* slot_panel_assoc;
BagLayer* bag_layer_node;
 
FloatingItem* global_floating_item_ptr;

int inv_floating_flag;
int inv_open_bag_count; // The number of open bags
int inv_item_count; // index used for the inv_items_array
int inv_bag_count;  // index used for the inv_bags_array

Item* inv_items_array[5000];  // Global array to hold item pointers.  Used by cleanup script only.
Bag* inv_bags_array[100]; // Again, store all created bags in this array so we can properly deallocate them later.


// =============== FUNCTIONS =============================================================


// function prototypes

function inv_close_bag(Bag*);
function _inv_do_float(FloatingItem*);
function _inv_drag_bag(Bag*, int drag_offset_x, int drag_offset_y);

function addBagLayer(Bag*);
function removeBagLayer(Bag*);
function reorderBagLayers();
function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel);
function removeSlotPanelAssoc(Slot* slot);

function getSlotPtrForPanelPtr(PANEL* panel_ptr);
function getBagPtrForPanelPtr(PANEL* panel_ptr);


// Callback function prototypes

void on_click_callback_function_ptr(int inv_action, int bag_id, int slot_id, int placed_item_id, int removed_item_id);
void on_float_end_callback_function_ptr();
void on_close_bag_callback_function_ptr(int bag_id);
void on_open_bag_callback_function_ptr(int bag_id);




// --------------- Inventory Function -----------------------------------
 
 
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  

}
 
function bagOnClick(PANEL* panel_ptr)
{
	Bag* bag;
	
	bag = getBagPtrForPanelPtr(panel_ptr);
	
	// Check to see if the player is dragging the panel
	
	if (bag->drag_region_top_left_x != bag->drag_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->drag_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->drag_region_top_left_x + (bag->drag_region_bottom_right_x - bag->drag_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->drag_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->drag_region_top_left_y + (bag->drag_region_bottom_right_y - bag->drag_region_top_left_y))))
		{
			_inv_drag_bag(bag,mouse_pos.x - bag->bag_panel->pos_x, mouse_pos.y - bag->bag_panel->pos_y);
		}
	}
	
	if (bag->close_region_top_left_x != bag->close_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->close_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->close_region_top_left_x + (bag->close_region_bottom_right_x - bag->close_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->close_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->close_region_top_left_y + (bag->close_region_bottom_right_y - bag->close_region_top_left_y))))
		{
			inv_close_bag(bag);
			return(0);
		}
	}

	// Bring bag to the front

	removeBagLayer(bag);		
	addBagLayer(bag);		

	reorderBagLayers();

}

function _inv_drag_bag(Bag* bag, int drag_offset_x, int drag_offset_y)
{
	int i;
		
	while(mouse_left)
	{
		
		vec_set(mouse_pos,mouse_cursor);
					
		// Move bag
		bag->bag_panel->pos_x = mouse_pos.x - drag_offset_x;
		bag->bag_panel->pos_y = mouse_pos.y - drag_offset_y;
		
		// Move all slots
		for (i=0; i < bag->_slot_count; i++)
		{
			bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + bag->bag_panel->pos_x;
			bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + bag->bag_panel->pos_y;
		}		
		
		wait(1);
	}
}

function slotOnClick(PANEL* clicked_panel)
{

	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	// player clicked on item in inventory while not floating an item
	
	diag("test1");
	
	if (global_floating_item_ptr->item == NULL)
	{
		diag("test2");

		if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
		{
			
			diag("\ngrab started\n");
			
			// optionally callback with action, bag_id, slot_id, item_id
			if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);


			// Create the floating panel
			
			global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
			
			// Set the item and panel image of the floating item structure.  This effectively "floats"
			// the item that was stored in the inventory slot.
			
			global_floating_item_ptr->item = clicked_slot->item;
			global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
			global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
			
			// Set the item pointer of the clicked on slot to NULL
			
			clicked_slot->item = NULL;
			
			// Restore inventory slot image to be the default background image
			
			clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			

			inv_floating_flag = 1;
			_inv_do_float(global_floating_item_ptr);
			

		}
	}
	else
	{
		diag("test3");

		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
				
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
	
}

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
		
}



function _inv_do_float(FloatingItem* floating_item)
{
	proc_mode = PROC_LATE;
		
	mouse_mode = 4;
	mouse_pointer = 1;
	 
	while(inv_floating_flag == 1)
	{
		floating_item->floating_item_panel.pos_x = mouse_pos.x + 10;
		floating_item->floating_item_panel.pos_y = mouse_pos.y + 10;
		wait(1);		
	}

	// optionally do a callback when floating ends
		
	if (on_float_end_callback_function_ptr) on_float_end_callback_function_ptr();

}

function inv_float_item(Item* item)
{
	
	global_floating_item_ptr->item = item;
	global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
	global_floating_item_ptr->floating_item_panel->bmap = bmap_create(item->floating_icon);
	
	global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
	
	inv_floating_flag = 1; // set global floating flag
	
	_inv_do_float(global_floating_item_ptr);
	
	return global_floating_item_ptr;
}


function inv_create_bag(int bag_id, STRING* image_name)
{
	Bag* bag;
	bag = new(Bag);
	
	bag->image_name = image_name;
	bag->id = bag_id;
	
	// Initialize slot_count to 0
	bag->_slot_count = 0;
	bag->is_open = 0;
	
	// Add bag to global array for cleanup purposes

	inv_bags_array[inv_bag_count] = bag;
	inv_bag_count++;
	
	return bag;
}

function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->drag_region_top_left_x = top_left_x;	
	bag->drag_region_top_left_y = top_left_y;	
	bag->drag_region_bottom_right_x = bottom_right_x;	
	bag->drag_region_bottom_right_y = bottom_right_y;
}

function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->close_region_top_left_x = top_left_x;	
	bag->close_region_top_left_y = top_left_y;	
	bag->close_region_bottom_right_x = bottom_right_x;	
	bag->close_region_bottom_right_y = bottom_right_y;
}

function inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position)
{
	bag->bag_panel = pan_create("",bag_layer_node);
	bag->bag_panel->bmap = bmap_create(bag->image_name);
	bag->bag_panel->event = bagOnClick;

	bag->is_open = 1;
	
	int i;
	
	// Add slots
	
	for (i=0; i < bag->_slot_count; i++)
	{
		
		bag->slots[i]->slot_panel = pan_create("",slot_layer);
		
		if (bag->slots[i]->item == NULL)
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->background_image);
		}
		else
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->item->inventory_icon);
		}
		
		bag->slots[i]->slot_panel->event = slotOnClick;
		bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + panel_x_position;
		bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + panel_y_position;
		
		// Make the new slot panel visible
		bag->slots[i]->slot_panel->flags |= VISIBLE;
		
		// Add this panel and slot to the linked list
		addSlotPanelAssoc(bag->slots[i],bag->slots[i]->slot_panel);
	}
	
	bag->bag_panel->pos_x = panel_x_position;
	bag->bag_panel->pos_y = panel_y_position;
		
	bag->bag_panel->flags |= VISIBLE;
	
	if (on_open_bag_callback_function_ptr) on_open_bag_callback_function_ptr(bag->id);
	
	inv_open_bag_count++;
	
	// Add the pointer to this bag to the front of a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	addBagLayer(bag);
	reorderBagLayers();
	
}

function inv_close_bag(Bag* bag)
{
	if (bag == NULL) 
	{
		diag("\nWARNING: inv_close_bag called with argument NULL\n");
		return 0;
	}

	bag->is_open = 0;
	
	int i;
	
	for (i=0; i < bag->_slot_count; i++)
	{
		// Remove each slot panel
		pan_remove(bag->slots[i]->slot_panel);
		
		// Remove the slot from the associative array
		removeSlotPanelAssoc(bag->slots[i]);
	}

	// remove bag panel
	
	pan_remove(bag->bag_panel);
	
	if (on_close_bag_callback_function_ptr) on_close_bag_callback_function_ptr(bag->id);
		
	inv_open_bag_count--;
	
	// Remove the pointer to this bag from a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	
	removeBagLayer(bag);		
}

//***********************************************************************************************************************************************************************

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

// THIS FUNCTION CREATES AN ERROR IN MY REGULAR PROGRAM

function inv_insert_item_into_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				/*
				else // ADDED BY RUBEN
				if(bag->slots[i]->group_id == 1)
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				// END OF ADDED BY RUBEN
				*/
			}
		}
	}
	
	return 0;
}

function inv_cleanup()
{
	diag("\nStarting inventory cleanup\n");
	
	int i;
	int j;
	
	// Clean up items
	
	Item* item;
	
	for(i=0;i<inv_item_count;i++)
	{
		diag("\n   * cleaning up inventory item");
		item = inv_items_array[i];
		
		if (item != NULL)
		{
			free(item->floating_icon);
			free(item->inventory_icon);
			free(item);
			diag(" - success");
		}
	}
	
	// Clean up bags
	
	Bag* bag;
	
	for (i=0; i<inv_bag_count; i++)
	{
		diag("\n   * cleaning up bag");		
		bag = inv_bags_array[i];
		
		if (bag != NULL)
		{
			// Clean up slots in bag

			for (j=0; j < bag->_slot_count; j++)
			{
				diag("\n     - cleaning up slot");
				free(bag->slots[j]->background_image);
				free(bag->slots[j]);
			}			
			
			free(bag->image_name);
			free(bag);
		}		
	}
	
	free(global_floating_item_ptr);
	
	diag("\nCompleted inventory cleanup\n");
	
}


// ------------- Helpful functions --------------

function inv_get_bag_panel_ptr(Bag* bag)
{
	return bag->bag_panel;	
}

function inv_is_bag_open(Bag* bag)
{
	if (bag == NULL) return 0;
	return bag->is_open;
}

function inv_get_open_bag_count()
{
	return inv_open_bag_count;
}

function inv_is_floating()
{
	return inv_floating_flag;
}

function inv_is_item_in_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i]->item == item)
		{
			return 1;
		}
	}
	
	return 0;
}


// ------------- Create Callback Functions ---------

function set_on_click_callback(STRING* function_name) { on_click_callback_function_ptr = engine_getscript(function_name); }
function set_on_float_end_callback(STRING* function_name) { on_float_end_callback_function_ptr = engine_getscript(function_name); }
function set_on_close_bag_callback(STRING* function_name) { on_close_bag_callback_function_ptr = engine_getscript(function_name); }
function set_on_open_bag_callback(STRING* function_name) { on_open_bag_callback_function_ptr = engine_getscript(function_name); }



// --------------- linked-list functions --------------------------------

// ** list functions for managing bag z order

function addBagLayer(Bag* bag)
{
	if(bag_layer_node == NULL)
	{
		bag_layer_node = new(BagLayer);
		bag_layer_node->bag = bag;

		bag_layer_node->next = NULL;
		bag_layer_node->prev = NULL;
	}
	else
	{
		// Create a new BagLayer struct and put it at the beginning of the list
		BagLayer* new_bag_layer_node = new(BagLayer);
		new_bag_layer_node->bag = bag;
				
		bag_layer_node->prev = new_bag_layer_node;
		new_bag_layer_node->next = bag_layer_node;
		new_bag_layer_node->prev = NULL;
		
		bag_layer_node = new_bag_layer_node;
	}
	
}

function removeBagLayer(Bag* bag)
{
	int first_node = 1;
	
	BagLayer* iterator = bag_layer_node;
	
	while(iterator != NULL)
	{
		if (iterator->bag == bag)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;
			
			if (first_node) bag_layer_node = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function reorderBagLayers()
{
	int new_bag_layer = 90;
	int sanity_check = 0;
	int i;
	
	BagLayer* iterator = bag_layer_node;
	Bag* bag;
		
	while(iterator != NULL)
	{
		// Chage bag layer
		bag = iterator->bag;		
		layer_sort(bag->bag_panel,new_bag_layer);
		
		// Change bag's slot layers
		for (i=0; i < bag->_slot_count; i++)
		{
			layer_sort(bag->slots[i]->slot_panel,new_bag_layer + 1);
		}		
		
		new_bag_layer -= 3;
		iterator = iterator->next;
		
		sanity_check++;
		if (sanity_check > 100) 
		{
			diag("ERROR: reorderBagLayers has run amok!");
			break;
		}
	}
	
}

// ** list functions for storing associations between panels and slots

function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel)
{
	if(slot_panel_assoc == NULL)
	{
		slot_panel_assoc = new(SlotPanelAssoc);
		slot_panel_assoc->slot_panel = slot_panel;
		slot_panel_assoc->slot = slot;

		slot_panel_assoc->next = NULL;
		slot_panel_assoc->prev = NULL;
		
	}
	else
	{
		// Create a new slot_panel_assoc struct and put it at the beginning of the list
		SlotPanelAssoc* new_slot_panel_assoc = new(SlotPanelAssoc);
		new_slot_panel_assoc->slot_panel = slot_panel;
		new_slot_panel_assoc->slot = slot;
				
		slot_panel_assoc->prev = new_slot_panel_assoc;
		new_slot_panel_assoc->next = slot_panel_assoc;
		new_slot_panel_assoc->prev = NULL;
		
		slot_panel_assoc = new_slot_panel_assoc;
	}
}

function removeSlotPanelAssoc(Slot* slot)
{
	int first_node = 1;

	SlotPanelAssoc* iterator = slot_panel_assoc;
	
	while(iterator != NULL)
	{
		if (iterator->slot == slot)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;

			if (first_node) slot_panel_assoc = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function getSlotPtrForPanelPtr(PANEL* panel_ptr)
{
	SlotPanelAssoc* iterator = slot_panel_assoc;

	if (iterator == NULL) 
	{
		diag("\nWARNING: getStructForPanelPtr returned NULL.");
	}
	
	while(iterator != NULL)
	{
		if (iterator.slot_panel == panel_ptr)
		{
			return(iterator.slot);
		}
		iterator = iterator->next;
	}
	
	return NULL;
}

/* 

	getBagPtrForPanelPtr(PANEL* panel_ptr)
 
	Given a panel pointer, return a pointer to the bag having that panel.
	In this case, we're lucky because the bags are all stored in the
	global inv_bags_array.  Why not store the slots in a similar array? --
	Because they're constantly created and destroyed.
	
*/

function getBagPtrForPanelPtr(PANEL* panel_ptr)
{
	int i;
	Bag* bag;
	
	for (i=0;i<inv_bag_count;i++)
	{
		bag = inv_bags_array[i];
		
		if (bag->bag_panel == panel_ptr)
		{
			return bag;
		}	
	}
	
	return NULL;
	
}

Posted By: rayp

Re: Access variable from other program? - 12/28/13 07:56

...global var's ? shocked ...or "forward" the function ?
Code:
//////////////////////
// main.c
//////////////////////
STRING* mytextstr = "the global text to show";
...
..
////////////////////////////////
// "program"1.c / "program"2.c
////////////////////////////////
   ...
   ..
   mytextstr = "Iam a global string"; // (wont work see manual)
   ..
   ...



Code:
...
..
function aha_this_works(); // now blabla knows about the function below
..
...
function blabla(){
   aha_this_works();
}
...
..
//////////////////////
// "program"1.c
//////////////////////
function aha_this_works(){
   draw_text ("damn iam tired", 10,10, vector (255,0,0));
}


Or maybe its possible to change the order of your include's ?

You're talking about different "programs"...but i guess u mean "scripts" ? Or is your goal to have two running processes / tasks / games on one computer ? why ? Sry i dont get it grin
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 09:17

Yes, I guess I mean two scripts. However, I am using #include to include the second script to be used in my first script.

If there is a variable that is only saved in the second script, but I need to check that same variable value using the first script that did not declare it as a variable, how can I do that?
Posted By: WretchedSid

Re: Access variable from other program? - 12/28/13 09:18

Include pulls the other script into the current translation unit.
In other words: Your problem doesn't exist to begin with.
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 09:20

inventory.c is an open source script that allows anyone to make their own customized inventory bag for the player in their game. It is saved in its own script called inventory.c . Are you saying that I have to combine inventory.c and OrcStronghold.c in the same script, in order to allow me to use a variable only stored in inventory.c , but who's value is needed by OrcStronghold.c to compare to another value, in order to initiate an action?
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 09:23

Originally Posted By: JustSid
Include pulls the other script into the current translation unit.
In other words: Your problem doesn't exist to begin with.

So by using #include , it is basically making the two scripts a part of the same script?
Posted By: WretchedSid

Re: Access variable from other program? - 12/28/13 10:57

As far as the current translation unit is concerned: Yes. The include is replaced with the contents of the other script by the pre-processor.

By the way at whoever suggested global variables: Shame on you! Polluting the global namespace with variables is evil!
Posted By: Superku

Re: Access variable from other program? - 12/28/13 11:33

Quote:
By the way at whoever suggested global variables: Shame on you! Polluting the global namespace with variables is evil!

Using global variables isn't normal, but on Meth it is.
I don't understand the hate on global variables, they are awesome and I use literally thousands of them in my project. <3
Posted By: WretchedSid

Re: Access variable from other program? - 12/28/13 11:37

The problem is that every function has access to them and the large a project grows, the harder it gets to keep track of what is doing what with what and who is depending on which variable and who is writing into which...

To give you a hands on example, let me quote yourself:
Quote:
ground_contact, wie ich aber gerade feststellen musste, ist keine variable, die nur 0 oder 1 annimmt, sondern die zähle ich bis 16 hoch.... weil ich irgendwo irgendwann vor jahren mal die dauer des bodenkontaktes brauchte


English (translation by me):
Quote:
ground_contact is, as I just discovered, not a variable in the range of 0 to 1 but is incremented up to 16 because years ago I needed a the time of the ground contact


That basically sums up why global variables are considered bad practice. Class dismissed tongue
Posted By: Superku

Re: Access variable from other program? - 12/28/13 11:38

Sadly this does not prove anything, it could have been a member of a struct or anything different but no global variable and it would have resulted in the same problem.
Posted By: WretchedSid

Re: Access variable from other program? - 12/28/13 11:41

Where it is stored doesn't matter, the point was to provide meaningful encapsulation. Put it all into one big struct and you haven't changed the problem one bit, just moved it around to another namespace. The point is to minimize the scope of access.

I mean, there is a reason why it's universally accepted as bad practice and anti-pattern, I don't make this stuff up just to annoy people.
Posted By: Superku

Re: Access variable from other program? - 12/28/13 11:46

I still don't see a reason. I can understand that there may be some problems when you work on a project in a big team or want to provide libraries for other users but even this could be solved with a proper naming convention.

#globalvariables4life
Posted By: MasterQ32

Re: Access variable from other program? - 12/28/13 12:00

@Superku:
Maybe the best example:
target, result, hWnd, player, my, me, you, your, nullvector, mtl, camera...

Imagine how often you need a local variable with this name but not with the same type.

Code:
ENTITY *camera = ent_create("camera.mdl", vector(16, 324, 123), follow_player);
camera->x = 5; // What variable do i modify? global VIEW* camera or local ENTITY* camera?

TraceResult *result = x_trace(from, to, USE_POLYGON); // Using custom tracing
if(result->isHit) { // Doesn't even compile, because result is a var and it is global
   error("I hit something!");
}



@Sid: Thanks for teaching a good code discipline wink

EDIT:
In short version: Every single global variable takes your possibility of thousands of local variables.
Posted By: Superku

Re: Access variable from other program? - 12/28/13 12:16

Yes, I see, but given that you have an (almost) unlimited pool of possible variable names and you should know that those GStudio variables overwrite local variables (which I find a little stupid, though) you only have to take a very little amount of care and creativity to overcome this problem.
Global variables are useful for a number of things, they are not 100% evil.
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 20:25

Originally Posted By: JustSid
As far as the current translation unit is concerned: Yes. The include is replaced with the contents of the other script by the pre-processor.

By the way at whoever suggested global variables: Shame on you! Polluting the global namespace with variables is evil!

Okay. Let say I create a function named active_weapon_slot() in OrcStronghold.c , as shown below:

Code:
function active_weapon_slot()
{
	if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx")) 
     {
          active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
     }
     else
     {
          ent_remove(active_sword);
     }
}



Now lets say I use the inv_create_item() function (taken from inventory.c) in the main function of OrcStronghold.c , as shown below:

Code:
// Inside OrcStronghold.c

function main()
{
   ...

item_shield = inv_create_item(1,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(1,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(0,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(0,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(1,0,"gold_coins.pcx","gold_coins.pcx");



In this last piece of code, I just created five items (.pcx images of equipment items) to be used to populate the slots of the inventory bag. I can drag these images among the different slots of the inventory bag, if I chose to.

However, I still have not created the slots themselves for the inventory bag, in order to put items into. I now perform that action here within the same OrcStrongholdMain.c main function:

Code:
...

   // ACTIVE ITEM SLOT
   
   active_weapon_slot = inv_add_slot_to_bag(bag, 0, 1, 
      "leather_texture.pcx", 9, 60); // 3RD VALUE "1" (which
      //    belongs to group_id variable), ONLY EQUIPMENT 
      //    ITEMS WITH group_id value = 1 CAN BE INSERTED 
      //    INTO THIS SLOT.  ONLY WEAPON ITEMS ARE ASSIGNED
      //    group_id = 1 .  ALL NON-WEAPON ITEMS ARE ASSIGNED 
      //    group_id = 0 , SO ONLY WEAPON ITEMS CAN BE 
      //    INSERTED INTO THIS SLOT.  I SET 
      //    active_weapon_slot EQUAL TO THIS SLOT.  
      //    "active_weapon_slot()" is a function in 
      //    OrcStronghold.c , outside the main function.

   // EACH ROW OF INVENTORY BAG IS SPACED OUT BY 64 HEIGHT
   // FIRST ROW OF INVENTORY BAG

   inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
   inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);
   inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
   inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
      // NOTICE THAT THE THIRD VALUE OF THESE SLOTS 
      //    ARE ASSIGNED THE VALUE 0 (zero).  THE REASON FOR 
      //    THIS IS BECAUSE THESE ITEMS ARE NOT WEAPONS, 
      //    THEREFORE, I ASSIGN THEIR group_id VARIABLE TO 0.

   ...



So in the last code above, I created an inventory bag with five slots. The top slot is reserved as the "active weapon" slot. This slot checks to see what the group_id is of an equipment item (.pcx image). If the group_id of the image is 1, that image can be placed in that slot. If the group_id of the equipment item is not 1 (like zero), then the equipment item cannot be placed in this slot.

I also created four other slots underneath the "active weapon" slot. These four slots can accept any items, weapon or non-weapon. That is because their group_id value (3rd value) is equal to 0.

Now, I also created the function active_weapon_slot() in OrcStronghold.c , before the main function. This function is supposed to represent the "active weapon" slot in the inventory bag. Whatever .pcx image of a weapon is placed in this "active weapon" slot inside the inventory bag, that is the weapon that the player should be armed with, in the player's hand, ready to use.

This is the code of function active_weapon_slot() that is trying to accomplish this:

Code:
// Inside OrcStronghold.c

function active_weapon_slot()
{
	if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx")) 
     {
          active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
     }
     else
     {
          ent_remove(active_sword);
     }
}



The function above is comparing the floating_icon variable's string, to the string "steel_sword.pcx". The variable floating_icon comes from inventory.c , and is used in the function inv_create_item , that we used earlier to create equipment item .pcx images, to be used to populate slots in the inventory bag. The function inv_create_item() is shown here:

Code:
// Inside inventory.c

...

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
}



As you see in the code above, floating_icon is the third variable taken as an argument in the inv_create_item function. However, if you notice in the code before last, I am trying to access the string value of that floating_icon variable (that is used as an argument in inv_create_item() inside inventory.c script) from the OrcStronghold.c script , in order to compare it with the string value "steel_sword.pcx". "steel_sword.pcx" is the file name of the sword image that is used to populate the inventory bag slots. If floating_icon string value of the active weapon slot equals "steel_sword.pcx", I want to attach a .mdl sword model to the player's hand, which is shown in the code above last.

When I compile this, this is my error:

Compiling ORCSTRONGHOLD.C - [Esc] to abort......
Error in 'line 180:
'floating_icon' : is not a member of 'BOOL'
< if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx"))
.. 0.108 sec
Error compiling ORCSTRONGHOLD.C
Error E355: Startup failure - any key to abort

Even though I #include inventory.c at the beginning of OrcStronghold.c , either I am using the function active_weapon_slot incorrectly, or I am not able to access the floating_icon value in the active weapon slot for some reason.

Do you know what I am doing wrong?
Posted By: Ruben

Re: Access variable from other program? - 12/28/13 20:36

Speaking in layman's terms, when a picture of a sword is inside the "active weapon" slot of the inventory bag, I want my player to be armed with a sword. If a picture of a mace is inside the "active weapon slot" of the inventory bag, I want my player to be armed with a mace; etc.

That is what this code is trying to accomplish.

Should I post this in a different thread that is beyond the "Starting with Gamestudio" thread?
Posted By: Ruben

Re: Access variable from other program? - 12/29/13 01:27

I will attempt to explain this in simpler terms again. It seems very hard for me to communicate this problem to people. If people on this thread cannot understand my problem after trying to explain it here, I will have no choice but to take this to a different thread beyond "Starting with Gamestudio". So here it goes:
Code:
Script:     OrcStronghold.c
Functions:  main()
            active_weapon_slot()
Actions:    #include "inventory.c" in beginning of script.
            In Main():  Uses inv_create_item() function 
               (stored in inventory.c) to process .pcx images 
               of equipment items, like sword, mace, gold, 
               apple, etc., so that their .pcx images can be 
               used in the inventory bag GUI as equipment 
               item images that can be placed in slots, 
               representing equipment items in the player's 
               inventory.
            In Main():  Uses inv_add_slot_to_bag() function 
               (stored in inventory.c) to add slots in the 
               inventory bag.  The programmer can create as 
               many slots as she/he wants for the inventory 
               bag.  The function name "active_weapon_slot" 
               is set equal to the inv_add_slot_to_bag 
               instance that is supposed to represent the 
               slot used for arming the player with a weapon.
            In active_weapon_slot():  Tries to compare the 
               variable string stored in floating_icon 
               variable (which is an argument in 
               inv_create_item() function, stored in 
               inventory.c) against the string 
               "steel_sword.pcx".  The file name 
               "steel_sword.pcx" is an argument passed to the 
               inv_create_item() function from 
               OrcStronghold.c main() function, to allow an 
               image of a sword representing a sword in 
               inventory, that can be used among the slots in 
               the inventory bag.

Script:     inventory.c
Functions:  inv_add_slot_to_bag(Bag* bag, int slot_id, int 
               group_id, STRING* default_image, int 
               rel_x_pos, int rel_y_pos)
            inv_create_item(item_id, group_id, STRING* 
               floating_icon, STRING* inventory_icon)
Actions:    inv_add_slot_to_bag() function creates a slot for 
               a custom made inventory bag for the player.
            inv_create_item() function allow a .pcx image to 
               be used in the inventory bag, representing an 
               equipment item.



Code:

Code:
// OrcStronghold.c

#include "inventory.c"

...

function active_weapon_slot()
{
   if(str_cmp(active_weapon_slot.floating_icon, "steel_sword.pcx")) 
   {
      active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
   }
   else
   {
      ent_remove(active_sword);
   }
}

...

function main()
{
   ...

   item_shield = inv_create_item(1,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(1,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(0,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(0,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(1,0,"gold_coins.pcx","gold_coins.pcx");
   
   ... 
   
   // START OF INVENTORY BAG
 
   // ACTIVE ITEM SLOT
   
   active_weapon_slot = inv_add_slot_to_bag(bag, 0, 1, "leather_texture.pcx", 
      9, 60); 

   inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
   inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);
   inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
   inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
	
   ...
   
}


Code:
// inventory.c

...

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
   // Create item and assign images
	
   Item* item = new(Item);
   item->floating_icon = floating_icon;		
   item->inventory_icon = inventory_icon;
   item->id = item_id;
   item->group_id = group_id;
	
   // Add item to global array for cleanup purposes

   inv_items_array[inv_item_count] = item;
   inv_item_count++;
	
   return item;		
}

...

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
   Slot* new_slot;
   new_slot = new(Slot);

   // Set the position for the new slot
	
   new_slot->rel_x_pos = rel_x_pos;
   new_slot->rel_y_pos = rel_y_pos;	
   new_slot->background_image = default_image;
   new_slot->item = NULL;
   new_slot->id = slot_id;
   new_slot->group_id = group_id;
   new_slot->bag_id = bag->id;	
		
   bag->slots[bag->_slot_count] = new_slot;
	
   bag->_slot_count += 1;	
}

...



How can I get OrcStronghold.c to access the floating_icon value (stored in inv_create_item() function, which is stored in inventory.c script) for the "active weapon" slot, using the active_weapon_slot() function in OrcStronghold.c ?

I think this is about the simplest way that I can try to explain this.

Posted By: xbox

Re: Access variable from other program? - 12/29/13 02:20

From what I am understanding, by the looks of part of your code such as
Code:
Slot* new_slot;
new_slot = new(Slot);


you are trying to use structs. You cannot (as far as I am aware) store variables in functions. Functions are just routines or methods that allow you to modify data, call other routines, etc. You can do as the others were saying and save these variables to global variables so that you can always access them, However the downside to that is if you decide to make more inventory slots, you must go add more global variables to match the new slots.

Back to using stucts. Structs are the best way to go in this situation because for every new "slot" you want to add, create a new "instance" of a slot struct and now you can easily access those variables per instance. example
Code:
typedef struct{
var rel_x_pos, rel_y_pos;
STRING* background_image;
var item;
var id;
var group_id;
var bag_id;
} Slot;

If you have already done that, sorry for typing code.
Once that is done, if you have stored the instances in an array example.
Code:
Slot* inv_slots[100];
inv_slots[0] = new Slot;


you could easily access the variables like this
Code:
inv_slots[21].item = 2; // or what ever you want to do with it.
//or change the background picture like this.
inv_slots[53].background_image = "newBackground.pcx";


I hope this helps. If not I sincerely apologize.
Best wishes!
Posted By: Ruben

Re: Access variable from other program? - 01/01/14 20:18

Thank you xbox. I think you are on the right track.

I am trying to use structs now in my situation. However, for some reason I am still not able to attach a sword to my player's hand when I drag a sword image toward the active weapon slot in the player's inventory bag.

So far, this is what I have done in my code:

OrcStronghold.c
Code:
// OrcStronghold.c

#include "Player.c"

...

Item* inv_slots[13];
inv_slots = new(Item);

...

function main()
{
   ...

   // Creating equipment items to be used in inventory bag (.pcx images to click
   //    and drag among slots in inventory bag)

   item_shield = inv_create_item(1,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(1,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(0,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(0,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(1,0,"gold_coins.pcx","gold_coins.pcx");

   bag = inv_create_bag(1,"leather_seam.pcx");  // <---- added this line

   // START OF INVENTORY BAG
   
   // ACTIVE ITEM SLOT
   
   inv_slots[0] = inv_add_slot_to_bag(bag,0,1,"leather_texture.pcx",9,60); 
      // Active Weapon slot

   // EACH ROW OF INVENTORY BAG IS SPACED OUT BY 64 HEIGHT
   // FIRST ROW OF INVENTORY BAG

   inv_slots[1] = inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
   inv_slots[2] = inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);
   inv_slots[3] = inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
   inv_slots[4] = inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
	
   // SECOND ROW OF INVENTORY BAG
	
   inv_slots[5] = inv_add_slot_to_bag(bag,5,0,"leather_texture.pcx",9,214);
   inv_slots[6] = inv_add_slot_to_bag(bag,6,0,"leather_texture.pcx",70,214);
   inv_slots[7] = inv_add_slot_to_bag(bag,7,0,"leather_texture.pcx",130,214);
   inv_slots[8] = inv_add_slot_to_bag(bag,8,0,"leather_texture.pcx",190,214);
	
   // THIRD ROW OF INVENTORY BAG
	
   inv_slots[9] = inv_add_slot_to_bag(bag,9,0,"leather_texture.pcx",9,278);
   inv_slots[10] = inv_add_slot_to_bag(bag,10,0,"leather_texture.pcx",70,278);
   inv_slots[11] = inv_add_slot_to_bag(bag,11,0,"leather_texture.pcx",130,278);
   inv_slots[12] = inv_add_slot_to_bag(bag,12,0,"leather_texture.pcx",190,278);

   if(str_cmp(inv_slots[0].floating_icon, "steel_sword.pcx")) 
   {
        active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
   }
   else
   {
        ent_remove(active_sword);
   }

   ...
}


Code:
// Player.c

#include "inventory.c"

...

// Attaches a weapon to player's hand

action attach_weapon() 
{
   set(my,PASSABLE);
   proc_mode = PROC_LATE;
	
   while (you != NULL) 
   {
      vec_for_vertex(temp.x,you,997); //hand palm base: Vector # 987
      vec_for_vertex(temp2.x,you,968); //hand palm tip: Vector # 982
      vec_set(my.x,temp.x);
      vec_diff(temp.x,temp2.x,temp.x);
      vec_to_angle(my.pan,temp.x); // ERROR "'pan' is not a member of 'VECTOR'
      vec_set(my.pan,my.pan);
 
      wait(1);
   }
}

...


Code:
// inventory.c

...

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
   PANEL* slot_panel;
	
   int id;
   int group_id;
   int rel_x_pos;
   int rel_y_pos;
   int width;
   int height;
	
   STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
   int id;
   int is_open;
	
   int drag_region_top_left_x;
   int drag_region_top_left_y;
   int drag_region_bottom_right_x;
   int drag_region_bottom_right_y;

   int close_region_top_left_x;
   int close_region_top_left_y;
   int close_region_bottom_right_x;
   int close_region_bottom_right_y;
	
   PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;     
} Bag;

...

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
   // Create item and assign images
	
   Item* item = new(Item);
   item->floating_icon = floating_icon;		
   item->inventory_icon = inventory_icon;
   item->id = item_id;
   item->group_id = group_id;
	
   // Add item to global array for cleanup purposes

   inv_items_array[inv_item_count] = item;
   inv_item_count++;
	
   return item;		
}

...

function inv_create_bag(int bag_id, STRING* image_name)
{
   Bag* bag;
   bag = new(Bag);
	
   bag->image_name = image_name;
   bag->id = bag_id;
	
   // Initialize slot_count to 0
   bag->_slot_count = 0;
   bag->is_open = 0;
	
   // Add bag to global array for cleanup purposes

   inv_bags_array[inv_bag_count] = bag;
   inv_bag_count++;
	
   return bag;
}

...

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
   Slot* new_slot;
   new_slot = new(Slot);

   // Set the position for the new slot
	
   new_slot->rel_x_pos = rel_x_pos;
   new_slot->rel_y_pos = rel_y_pos;	
   new_slot->background_image = default_image;
   new_slot->item = NULL;
   new_slot->id = slot_id;
   new_slot->group_id = group_id;
   new_slot->bag_id = bag->id;	
		
   bag->slots[bag->_slot_count] = new_slot;
	
   bag->_slot_count += 1;	
}

...



When I compile OrcStronghold.c , it does not produce any syntax errors, but when I access my inventory bag and drag a sword image ("steel_sword.pcx") over to the active weapon slot, and get out of the inventory bag, my player is not being armed with the sword.

Does anyone know what I may be doing wrong in trying to make this happen?
Posted By: xbox

Re: Access variable from other program? - 01/01/14 21:07

where is the code showing what happens when you drag the sword to the active slot?

From the above code, I see that you have the active weapon slot set with what I assume to be just an empty square to represent an inventory space. I think what you need to do via code is set
Code:
inv_slots[0] = item_sword;


For some reason though, I feel like the visual inventory will get messed up by overwriting the inventory to the sword, although the sword should be created.
Posted By: Ruben

Re: Access variable from other program? - 01/01/14 21:26

There seems to be a lot going on with the code that drags the sword to the active slot, which I don't even fully understand. Here is the entire open source inventory.c script that I am using:

Code:
// 
// Inventory.c - programmed by Bret Truchan.  You are welcome to use this inventory
// system in the creation of commercial or free games.  You may not use it for any
// other purpose.
// 

/*


DOCUMENTATION

Table of Contents

   I. Introduction
  II. Essentials: inv_init() and inv_cleanup()
 III. Creating items for your inventory
  IV. Making your first bag
   V. Opening and Closing bags
  VI. Setting bag close and drag regions
 VII. Adding items to bags

VIII. Item Groups
  IX. Callbacks
  X. Other helpful functions


I. Introduction
---------------

Hello fellow programmer!  I hope that you can find the following inventory
system useful.  My main goal when making this inventory system was to decouple
the inventory system from the rest of the game code.  I also wanted to make it
as easy as possible to create and manage your inventory system.

This inventory has the following features:

1. Easy to use
2. Supports multiple bags
3. Handles the layering of bags for you
4. Supports callbacks for inventory events
5. Supports item "groups". (For example, gerbils can only be put in gerbil
slots.)

I modeled the inventory system after World of Warcraft.  One limitation to this
system is that slots in bags really need to be the same size.  I know how to 
fix this so, for example, your sword would show up huge in the sword slot but
small in a backpack slot, but I'll have to save that for a later release.



II. Essentials: inv_init() and inv_cleanup()
--------------------------------------------

Let's dive right in.  Creating your inventory is done in your lite-c code. 
You should not need to modify inventory.c.  Before anything else, include
inventory.c in your code, like so:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c" // <---- ADDED THIS

 void main()
 {
   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   // etc..

Add the inv_init(); function call to your main loop as shown above.  Because
inventory.c uses some low level C structures, you need to call inv_cleanup()
just before your game closes.


III. Creating items for your inventory
--------------------------------------

Let's skip ahead and create some images that will be needed for your
inventory.  If you have the demo for this inventory code, you can use my demo
images.

  pack.pcx - The is the background image of your inventory pack.
  slot_bg.pcx - The background image of an empty slot.
  item1.pcx - An icon of an item, such as a sword.  This should be the same
size as slot_bg.pcx.

Ok, back to items....

Items are strange.  You might think of an item like a "sword" or "gun". 
However, this inventory system is NOT trying to control how you manage items
for your game.  Although you might have a "sword" item in your inventory, the
structure that's passed around in the inventory code should NOT have
attributes such as "damage" or "weight".

Let's move ahead with an example of adding your first item - A pile of sand.
Maybe this pile of sand will go into your nephew's Christmas Stocking
because he ate all your friggin' cookies?!

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");


See that inv_create_item(...) statement?  inv_create_item() creates an abstract
item in your inventory system. Let's break it down:

 item_pointer = inv_create_item(item_id,group_id,floating_icon,inventory_icon);

Arguments:

 item_id - You make this up.  It can be anything that you want.  It doesn't affect the inventory engine.
 
 group_id - Later on, slots will also have a group id.  Items can only be put into slots with the right group id.

 floating_icon - The image used for the item while it's being dragged around the inventory system.

 inventory_icon - The image for displaying the item when the item is in a slot.

To reiterate, we introduced a new item into our inventory system.  We gave it an item id of 1, which really doesn't mean anything.  We gave it a group_id = 0, which means that the item can be placed into any slot having group_id=0.  We choose the same image "item1.pcx" for the icon used to "float" the item around in the inventory as well as the icon that represents the item in a slot.  That's good enough for now.  We'll keep moving forward..


IV. Making your first bag
-------------------------

There are a few terms that I loosly introduced above.  Your inventory may have multiple "bags".  Bags have multiple "slots", and slots may contain items.  Let's make our first bag.  Luckily, it's pretty easy:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;
 Bag* bag; // <---- added this line

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");
   bag = inv_create_bag(1,"pack.pcx");  // <---- added this line


Easy!  When you do this, the bag does not appear on the screen.  We'll handle that later.  For now, let's look closely at the
inv_create_bag() function:

   bag = inv_create_bag(bag_id,bag_image);

Arguments

 bag_id - You make this up.  It's not used within the inventory system, but it can be useful when handling callbacks.  We'll  
 discuss callbacks later on.

 bag_image - This should be an image of your open inventory bag.


Creating a bag is only half the battle.  Generally, you use the inv_add_slot_to_bag() function to add
a slot to your bag.  Here's the generic version:

  function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)

Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image

Here's a real world example of creating 4 slots to your bag:

  inv_add_slot_to_bag(bag,1,0,"slot_bg.pcx",9,38);
  inv_add_slot_to_bag(bag,2,0,"slot_bg.pcx",44,38);
  inv_add_slot_to_bag(bag,3,0,"slot_bg.pcx",78,38);
  inv_add_slot_to_bag(bag,4,0,"slot_bg.pcx",112,38);


V. Opening and Closing bags
---------------------------

Opening bags is easy:

  inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position);

That's it!  Here's use a real world example:

  inv_open_bag(bag, 100,100);

Closing your bag is even easier:

  inv_close_bag(bag);

We haven't added items to bags yet, but you'll see that it's very easy. When you open and close bags, the bags remember what items they contained.  You don't need to re-add the items.


VI. Setting bag close and drag regions
--------------------------------------

This inventory system allows you to drag bags around the screen and close them.  It's optional.  All you need to do is tell the inventory system where the drag region and close region are on the bag image.  Here's an example:

  inv_set_bag_drag_region(bag,5,3,128,18);
  inv_set_bag_close_region(bag,129,0,148,19);

The arguments are:

 function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
 function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)

Quick note:  For multiple bags, the inventory code automatically handles which bag should be "on top" if they overlap.


VII. Adding items to bags
-------------------------

Believe it or not, you're almost done.  Adding items to the inventory system can be done in two ways.  First, you can add an item directly to a bag.  Alternatively, you can create an item and immediately have it "float" (which means that the icon is visible and is being dragged by the mouse).

Adding an item directly to a bag:

  function inv_insert_item_into_bag(Bag* bag, Item* item)

For example:

  inv_insert_item_into_bag(bag,item_sand);

  (This function will return 1 if there was room in the bag for the item, otherwise 0.)

... OR "Floating" a new item:

  function inv_float_item(Item* item)

For example:

  function inv_float_item(item_sand);

That's it!


VIII. Item Groups
-----------------

Item groups are super easy.  Group_id 0 is special.  If you assign group_id = 0 to a slot, that slot can hold ANY
item.  Let's pretend that you want to make a weapon slot that can ONLY hold weapons.  When you create the sword item,
use the group_id = 4;  Then, when you create the sword slot, set its group_id = 4 too.  Done!


IX. Callbacks
-------------

If you need to know when certain events happen in the inventory system, you'll want to use the callbacks.  I'll explain with an example.  Let's say that you want to know whenever a bag is opened.  First, you need to define a function in your lite-c that will be called when a bag is open.  An open-bag callback function looks like:

a) open_bag_callback

  // put something like this in your lite-c

  function bag_was_opened(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_open_bag_callback() like so:

  set_on_open_bag_callback("bag_was_opened");

Whenever a bag is opened, your function bag_was_opened() will be called.  The bag_id of the opened bag will be passed into your function automatically.  Remember when we first created a bag and I said that the bag_id was useless?  I lied.  Here's where it comes into play.  You can tell which bag was opened by looking at the bag_id that's passed in to your callback function.

b) on_click_callback

This is most complicated callback.  It's triggered whenever someone clicks on a slot.  To use it, add something like this to your lite-c:

  function slot_was_clicked(int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id)
  {
    if (action == INV_ITEM_PLACED)
    {
       // item was placed in bag
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot  
       // removed_item_id is 0 and should be ignored
    }
    if (action == INV_ITEM_REMOVED)
    {
       // item was removed from bag  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is 0 and should be ignored 
       // removed_item_id is the item id that was removed from the slot
    }
    if (action == INV_ITEM_SWAPED)
    {
       // item was put in to a slot that already contained an item, so they were swapped  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot 
       // removed_item_id is the item id that was removed from the slot
    }
  }

And register your callback like:

  set_on_click_callback("slot_was_clicked");


c) on_bag_close_callback

This is just like on_bag_open_callback.  Here's an example:

  function bag_was_closed(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_close_bag_callback() like so:

  set_on_close_bag_callback("bag_was_closed");



X. Other helpful functions
--------------------------

 PANEL* inv_get_bag_panel_ptr(Bag* bag); // given a bag, return its panel pointer
 inv_is_bag_open(Bag* bag); // returns 1 if the bag is open, otherwise 0
 inv_get_open_bag_count(); // returns the number of open bags
 inv_is_floating(); // returns 1 if the player is floating an inventory item
 inv_is_item_in_bag(Bag* bag, Item* item); // returns 1 if the item is in the bag


*/





// ============================ BEGIN CODE =================================


#define new(type) malloc(sizeof(type##))
#define delete(object) free(object)

#define bag_layer 1
#define slot_layer 2
#define floating_item_layer 94

#define INV_ITEM_PLACED 1
#define INV_ITEM_SWAPPED 2
#define INV_ITEM_REMOVED 3

/* 
	struct Item

	The item structure holds a single item's information.  Items are intended to 
	track inventory icons only.  They're not really meant to manage an entire
	game's items.  For example, you would NOT use the item struct to hold values
	such as damage or defense rating for a sword.  The id in the item struct is
	intended to help associate these inventory based items with whatever item
	management is used in the game.  The id is set by the game developer to
	any arbitrary value.  The id is used in callback functions.
	
*/

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
	PANEL* slot_panel;
	
	int id;
	int group_id;
	int rel_x_pos;
	int rel_y_pos;
	int width;
	int height;
	
	STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
	int id;
	int is_open;
	
	int drag_region_top_left_x;
	int drag_region_top_left_y;
	int drag_region_bottom_right_x;
	int drag_region_bottom_right_y;

	int close_region_top_left_x;
	int close_region_top_left_y;
	int close_region_bottom_right_x;
	int close_region_bottom_right_y;
	
	PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;
     
} Bag;


// === Floating Item ===

typedef struct
{
	Item* item;
	PANEL* floating_item_panel;
	
} FloatingItem;


// Ugly linked list for keeping track of panels and associated slots

typedef struct SlotPanelAssoc
{
	PANEL* slot_panel;
	Slot* slot;
	struct SlotPanelAssoc* next;
	struct SlotPanelAssoc* prev;
	
} SlotPanelAssoc;


// Another ugly linked list for keeping track of z-order of open bags

typedef struct BagLayer
{
	Bag* bag;
	struct BagLayer* next;
	struct BagLayer* prev;
	
} BagLayer;


// Global variables

SlotPanelAssoc* slot_panel_assoc;
BagLayer* bag_layer_node;
 
FloatingItem* global_floating_item_ptr;

int inv_floating_flag;
int inv_open_bag_count; // The number of open bags
int inv_item_count; // index used for the inv_items_array
int inv_bag_count;  // index used for the inv_bags_array

Item* inv_items_array[5000];  // Global array to hold item pointers.  Used by cleanup script only.
Bag* inv_bags_array[100]; // Again, store all created bags in this array so we can properly deallocate them later.


// =============== FUNCTIONS =============================================================


// function prototypes

function inv_close_bag(Bag*);
function _inv_do_float(FloatingItem*);
function _inv_drag_bag(Bag*, int drag_offset_x, int drag_offset_y);

function addBagLayer(Bag*);
function removeBagLayer(Bag*);
function reorderBagLayers();
function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel);
function removeSlotPanelAssoc(Slot* slot);

function getSlotPtrForPanelPtr(PANEL* panel_ptr);
function getBagPtrForPanelPtr(PANEL* panel_ptr);


// Callback function prototypes

void on_click_callback_function_ptr(int inv_action, int bag_id, int slot_id, int placed_item_id, int removed_item_id);
void on_float_end_callback_function_ptr();
void on_close_bag_callback_function_ptr(int bag_id);
void on_open_bag_callback_function_ptr(int bag_id);




// --------------- Inventory Function -----------------------------------
 
 
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  

}
 
function bagOnClick(PANEL* panel_ptr)
{
	Bag* bag;
	
	bag = getBagPtrForPanelPtr(panel_ptr);
	
	// Check to see if the player is dragging the panel
	
	if (bag->drag_region_top_left_x != bag->drag_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->drag_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->drag_region_top_left_x + (bag->drag_region_bottom_right_x - bag->drag_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->drag_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->drag_region_top_left_y + (bag->drag_region_bottom_right_y - bag->drag_region_top_left_y))))
		{
			_inv_drag_bag(bag,mouse_pos.x - bag->bag_panel->pos_x, mouse_pos.y - bag->bag_panel->pos_y);
		}
	}
	
	if (bag->close_region_top_left_x != bag->close_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->close_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->close_region_top_left_x + (bag->close_region_bottom_right_x - bag->close_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->close_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->close_region_top_left_y + (bag->close_region_bottom_right_y - bag->close_region_top_left_y))))
		{
			inv_close_bag(bag);
			return(0);
		}
	}

	// Bring bag to the front

	removeBagLayer(bag);		
	addBagLayer(bag);		

	reorderBagLayers();

}

function _inv_drag_bag(Bag* bag, int drag_offset_x, int drag_offset_y)
{
	int i;
		
	while(mouse_left)
	{
		
		vec_set(mouse_pos,mouse_cursor);
					
		// Move bag
		bag->bag_panel->pos_x = mouse_pos.x - drag_offset_x;
		bag->bag_panel->pos_y = mouse_pos.y - drag_offset_y;
		
		// Move all slots
		for (i=0; i < bag->_slot_count; i++)
		{
			bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + bag->bag_panel->pos_x;
			bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + bag->bag_panel->pos_y;
		}		
		
		wait(1);
	}
}

function slotOnClick(PANEL* clicked_panel)
{

	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	// player clicked on item in inventory while not floating an item
	
	diag("test1");
	
	if (global_floating_item_ptr->item == NULL)
	{
		diag("test2");

		if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
		{
			
			diag("\ngrab started\n");
			
			// optionally callback with action, bag_id, slot_id, item_id
			if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);


			// Create the floating panel
			
			global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
			
			// Set the item and panel image of the floating item structure.  This effectively "floats"
			// the item that was stored in the inventory slot.
			
			global_floating_item_ptr->item = clicked_slot->item;
			global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
			global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
			
			// Set the item pointer of the clicked on slot to NULL
			
			clicked_slot->item = NULL;
			
			// Restore inventory slot image to be the default background image
			
			clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			

			inv_floating_flag = 1;
			_inv_do_float(global_floating_item_ptr);
			

		}
	}
	else
	{
		diag("test3");

		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
				
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
	
}

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
		
}



function _inv_do_float(FloatingItem* floating_item)
{
	proc_mode = PROC_LATE;
		
	mouse_mode = 4;
	mouse_pointer = 1;
	 
	while(inv_floating_flag == 1)
	{
		floating_item->floating_item_panel.pos_x = mouse_pos.x + 10;
		floating_item->floating_item_panel.pos_y = mouse_pos.y + 10;
		wait(1);		
	}

	// optionally do a callback when floating ends
		
	if (on_float_end_callback_function_ptr) on_float_end_callback_function_ptr();

}

function inv_float_item(Item* item)
{
	
	global_floating_item_ptr->item = item;
	global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
	global_floating_item_ptr->floating_item_panel->bmap = bmap_create(item->floating_icon);
	
	global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
	
	inv_floating_flag = 1; // set global floating flag
	
	_inv_do_float(global_floating_item_ptr);
	
	return global_floating_item_ptr;
}


function inv_create_bag(int bag_id, STRING* image_name)
{
	Bag* bag;
	bag = new(Bag);
	
	bag->image_name = image_name;
	bag->id = bag_id;
	
	// Initialize slot_count to 0
	bag->_slot_count = 0;
	bag->is_open = 0;
	
	// Add bag to global array for cleanup purposes

	inv_bags_array[inv_bag_count] = bag;
	inv_bag_count++;
	
	return bag;
}

function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->drag_region_top_left_x = top_left_x;	
	bag->drag_region_top_left_y = top_left_y;	
	bag->drag_region_bottom_right_x = bottom_right_x;	
	bag->drag_region_bottom_right_y = bottom_right_y;
}

function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->close_region_top_left_x = top_left_x;	
	bag->close_region_top_left_y = top_left_y;	
	bag->close_region_bottom_right_x = bottom_right_x;	
	bag->close_region_bottom_right_y = bottom_right_y;
}

function inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position)
{
	bag->bag_panel = pan_create("",bag_layer_node);
	bag->bag_panel->bmap = bmap_create(bag->image_name);
	bag->bag_panel->event = bagOnClick;

	bag->is_open = 1;
	
	int i;
	
	// Add slots
	
	for (i=0; i < bag->_slot_count; i++)
	{
		
		bag->slots[i]->slot_panel = pan_create("",slot_layer);
		
		if (bag->slots[i]->item == NULL)
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->background_image);
		}
		else
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->item->inventory_icon);
		}
		
		bag->slots[i]->slot_panel->event = slotOnClick;
		bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + panel_x_position;
		bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + panel_y_position;
		
		// Make the new slot panel visible
		bag->slots[i]->slot_panel->flags |= VISIBLE;
		
		// Add this panel and slot to the linked list
		addSlotPanelAssoc(bag->slots[i],bag->slots[i]->slot_panel);
	}
	
	bag->bag_panel->pos_x = panel_x_position;
	bag->bag_panel->pos_y = panel_y_position;
		
	bag->bag_panel->flags |= VISIBLE;
	
	if (on_open_bag_callback_function_ptr) on_open_bag_callback_function_ptr(bag->id);
	
	inv_open_bag_count++;
	
	// Add the pointer to this bag to the front of a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	addBagLayer(bag);
	reorderBagLayers();
	
}

function inv_close_bag(Bag* bag)
{
	if (bag == NULL) 
	{
		diag("\nWARNING: inv_close_bag called with argument NULL\n");
		return 0;
	}

	bag->is_open = 0;
	
	int i;
	
	for (i=0; i < bag->_slot_count; i++)
	{
		// Remove each slot panel
		pan_remove(bag->slots[i]->slot_panel);
		
		// Remove the slot from the associative array
		removeSlotPanelAssoc(bag->slots[i]);
	}

	// remove bag panel
	
	pan_remove(bag->bag_panel);
	
	if (on_close_bag_callback_function_ptr) on_close_bag_callback_function_ptr(bag->id);
		
	inv_open_bag_count--;
	
	// Remove the pointer to this bag from a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	
	removeBagLayer(bag);		
}

//***********************************************************************************************************************************************************************

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

function inv_insert_item_into_bag(Bag* bag, Item* item)  // COULD THIS SOLVE THE PROBLEM?????????????????????????????????????????????????????????????????????
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				/*
				else // ADDED BY RUBEN
				if(bag->slots[i]->group_id == 1)
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				// END OF ADDED BY RUBEN
				*/
			}
		}
	}
	
	return 0;
}

function inv_cleanup()
{
	diag("\nStarting inventory cleanup\n");
	
	int i;
	int j;
	
	// Clean up items
	
	Item* item;
	
	for(i=0;i<inv_item_count;i++)
	{
		diag("\n   * cleaning up inventory item");
		item = inv_items_array[i];
		
		if (item != NULL)
		{
			free(item->floating_icon);
			free(item->inventory_icon);
			free(item);
			diag(" - success");
		}
	}
	
	// Clean up bags
	
	Bag* bag;
	
	for (i=0; i<inv_bag_count; i++)
	{
		diag("\n   * cleaning up bag");		
		bag = inv_bags_array[i];
		
		if (bag != NULL)
		{
			// Clean up slots in bag

			for (j=0; j < bag->_slot_count; j++)
			{
				diag("\n     - cleaning up slot");
				free(bag->slots[j]->background_image);
				free(bag->slots[j]);
			}			
			
			free(bag->image_name);
			free(bag);
		}		
	}
	
	free(global_floating_item_ptr);
	
	diag("\nCompleted inventory cleanup\n");
	
}


// ------------- Helpful functions --------------

function inv_get_bag_panel_ptr(Bag* bag)
{
	return bag->bag_panel;	
}

function inv_is_bag_open(Bag* bag)
{
	if (bag == NULL) return 0;
	return bag->is_open;
}

function inv_get_open_bag_count()
{
	return inv_open_bag_count;
}

function inv_is_floating()
{
	return inv_floating_flag;
}

function inv_is_item_in_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i]->item == item)
		{
			return 1;
		}
	}
	
	return 0;
}


// ------------- Create Callback Functions ---------

function set_on_click_callback(STRING* function_name) { on_click_callback_function_ptr = engine_getscript(function_name); }
function set_on_float_end_callback(STRING* function_name) { on_float_end_callback_function_ptr = engine_getscript(function_name); }
function set_on_close_bag_callback(STRING* function_name) { on_close_bag_callback_function_ptr = engine_getscript(function_name); }
function set_on_open_bag_callback(STRING* function_name) { on_open_bag_callback_function_ptr = engine_getscript(function_name); }



// --------------- linked-list functions --------------------------------

// ** list functions for managing bag z order

function addBagLayer(Bag* bag)
{
	if(bag_layer_node == NULL)
	{
		bag_layer_node = new(BagLayer);
		bag_layer_node->bag = bag;

		bag_layer_node->next = NULL;
		bag_layer_node->prev = NULL;
	}
	else
	{
		// Create a new BagLayer struct and put it at the beginning of the list
		BagLayer* new_bag_layer_node = new(BagLayer);
		new_bag_layer_node->bag = bag;
				
		bag_layer_node->prev = new_bag_layer_node;
		new_bag_layer_node->next = bag_layer_node;
		new_bag_layer_node->prev = NULL;
		
		bag_layer_node = new_bag_layer_node;
	}
	
}

function removeBagLayer(Bag* bag)
{
	int first_node = 1;
	
	BagLayer* iterator = bag_layer_node;
	
	while(iterator != NULL)
	{
		if (iterator->bag == bag)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;
			
			if (first_node) bag_layer_node = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function reorderBagLayers()
{
	int new_bag_layer = 90;
	int sanity_check = 0;
	int i;
	
	BagLayer* iterator = bag_layer_node;
	Bag* bag;
		
	while(iterator != NULL)
	{
		// Chage bag layer
		bag = iterator->bag;		
		layer_sort(bag->bag_panel,new_bag_layer);
		
		// Change bag's slot layers
		for (i=0; i < bag->_slot_count; i++)
		{
			layer_sort(bag->slots[i]->slot_panel,new_bag_layer + 1);
		}		
		
		new_bag_layer -= 3;
		iterator = iterator->next;
		
		sanity_check++;
		if (sanity_check > 100) 
		{
			diag("ERROR: reorderBagLayers has run amok!");
			break;
		}
	}
	
}

// ** list functions for storing associations between panels and slots

function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel)
{
	if(slot_panel_assoc == NULL)
	{
		slot_panel_assoc = new(SlotPanelAssoc);
		slot_panel_assoc->slot_panel = slot_panel;
		slot_panel_assoc->slot = slot;

		slot_panel_assoc->next = NULL;
		slot_panel_assoc->prev = NULL;
		
	}
	else
	{
		// Create a new slot_panel_assoc struct and put it at the beginning of the list
		SlotPanelAssoc* new_slot_panel_assoc = new(SlotPanelAssoc);
		new_slot_panel_assoc->slot_panel = slot_panel;
		new_slot_panel_assoc->slot = slot;
				
		slot_panel_assoc->prev = new_slot_panel_assoc;
		new_slot_panel_assoc->next = slot_panel_assoc;
		new_slot_panel_assoc->prev = NULL;
		
		slot_panel_assoc = new_slot_panel_assoc;
	}
}

function removeSlotPanelAssoc(Slot* slot)
{
	int first_node = 1;

	SlotPanelAssoc* iterator = slot_panel_assoc;
	
	while(iterator != NULL)
	{
		if (iterator->slot == slot)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;

			if (first_node) slot_panel_assoc = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function getSlotPtrForPanelPtr(PANEL* panel_ptr)
{
	SlotPanelAssoc* iterator = slot_panel_assoc;

	if (iterator == NULL) 
	{
		diag("\nWARNING: getStructForPanelPtr returned NULL.");
	}
	
	while(iterator != NULL)
	{
		if (iterator.slot_panel == panel_ptr)
		{
			return(iterator.slot);
		}
		iterator = iterator->next;
	}
	
	return NULL;
}

/* 

	getBagPtrForPanelPtr(PANEL* panel_ptr)
 
	Given a panel pointer, return a pointer to the bag having that panel.
	In this case, we're lucky because the bags are all stored in the
	global inv_bags_array.  Why not store the slots in a similar array? --
	Because they're constantly created and destroyed.
	
*/

function getBagPtrForPanelPtr(PANEL* panel_ptr)
{
	int i;
	Bag* bag;
	
	for (i=0;i<inv_bag_count;i++)
	{
		bag = inv_bags_array[i];
		
		if (bag->bag_panel == panel_ptr)
		{
			return bag;
		}	
	}
	
	return NULL;
	
}



I don't know if you can find it in there. I will look myself and see if I myself can find it.
Posted By: xbox

Re: Access variable from other program? - 01/01/14 21:42

I believe the part you're looking for is at the end of the function slotOnClick.

This seems to be were the item being dragged is being set to the slot in the inventory. So you need to check if the sword is placed in a specific slot.

I need to leave for work right now so I'll help more tomorrow.

EDIT: In your if statement where you are doing the strcmp instead of doing inv_slots[0].floating_icon try inv_slots[0]->floating_icon
Posted By: Ruben

Re: Access variable from other program? - 01/02/14 06:28

Well, I put this in the beginning of OrcStronghold.c :

Code:
Item* inv_slots[13];
inv_slots = new(Item);

ENTITY* active_sword;



I also changed the string comparison if statement in my main function (inside OrcStronghold.c) to:

Code:
if(str_cmp(inv_slots[0]->floating_icon, "steel_sword.pcx"))
   {
        active_sword = ent_create ("sword.mdl", my.x, attach_weapon);
   }
   else
   {
        ent_remove(active_sword);
   }



...and I am still getting the same results. I am able to place a .pcx image of a sword in the active weapon slot of my inventory bag, but it is not arming my player with a sword attached to its hand as a result.
Posted By: txesmi

Re: Access variable from other program? - 01/02/14 07:36

Hi,
I guess you have to use the module callbacks that are built for these cases. If you define and register the slot callback function it should be called when you click/drop on a slot.

Code:
// bags
#define MAIN_BAG_ID        1
#define TRADER01_BAG_ID    2
// slots
#define WEAPON_SLOT_ID     1
// groups
#define WEAPON_GROUP       1
// items
#define SWORD01_ID         101
#define SWORD02_ID         102
#define HAMMER01_ID        201
#define HAMMER02_ID        202


function fncMyCallback ( int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id )
{
	if ( bag_id == MAIN_BAG_ID )
	{
		if ( slot_id == WEAPON_SLOT_ID )
		{
			if ( removed_item_id != 0 )
			{
				// Remove the old weapon model
			}
			
			if ( ( placed_item >= SWORD01_ID ) && ( placed_item < HAMMER01_ID ) )
			{
				// Create the new sword model
			}
		}
	}
}

function main ()
{
	Bag *bag = inv_create_bag ( MAIN_BAG_ID, "leather_seam.pcx" );
	Slot *slot = inv_add_slot_to_bag ( bag, WEAPON_SLOT_ID, WEAPON_GROUP, "leather_texture.pcx", 9, 60 ); // Active Weapon slot
	Item *item_sword01 = inv_create_item ( SWORD01_ID, WEAPON_GROUP, "steel_sword.pcx", "steel_sword.pcx" );
	
	set_on_click_callback ( "fncMyCallback" );
}

Posted By: Ruben

Re: Access variable from other program? - 01/04/14 18:43

Thank you txesmi for your advice.

I am trying the callback functions, with still no luck. Maybe I am doing it wrong. This is what my code looks like so far:

OrcStrongold.c
Code:
// OrcStronghold.c

...

#include "inventory.c"

...

#define MAIN_BAG_ID        1
#define ACTIV_WPN_SLOT_ID  0
#define SWORD_ID           2

...

ENTITY* active_sword;

...

Item* item;
Bag* bag;
Slot* slot;

...

function slot_was_clicked(int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id) 
{
   bag = new(Bag);
   slot = new(Slot);
   item = new(Item);
	
   bag.id = bag_id;
   slot.id = slot_id;
   item.id = placed_item_id;
	
   if (occurrence == INV_ITEM_PLACED)
   {
      // item was placed in bag
      // bag_id is the id of the bag where the item was placed
      // slot_id is the id of the slot where the item was 
      //    placed 
      // placed_item_id is the item id that was placed 
      //    into the slot 
      // removed_item_id is 0 and should be ignored
      
      if (bag.id == MAIN_BAG_ID)
      {
         if (slot.id == ACTIV_WPN_SLOT_ID)
   	 {
   	    if (item.id == SWORD_ID)
   	    {
   	       active_sword = ent_create ("sword.mdl", my.x, 
                  attach_weapon);
            }
            else
            {
               ent_remove(active_sword);
	    }
	 }
      }   
   }
}

function main()
{

   ...

   item_shield = inv_create_item(0,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(1,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(2,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(3,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(4,0,"gold_coins.pcx","gold_coins.pcx");

   bag = inv_create_bag(1,"leather_seam.pcx");  // <---- added this line
   
   // START OF INVENTORY BAG
   
   // ACTIVE ITEM SLOT
   
   inv_add_slot_to_bag(bag,0,1,"leather_texture.pcx",9,60); // 3RD VALUE "1", ONLY ITEMS WITH THIS VALUE CAN BE INSERTED INTO THIS SLOT.

   // EACH ROW OF INVENTORY BAG IS SPACED OUT BY 64 VERTICAL HEIGHT
   // FIRST ROW OF INVENTORY BAG

   inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
   inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);
   inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
   inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
	
   // SECOND ROW OF INVENTORY BAG
	
   inv_add_slot_to_bag(bag,5,0,"leather_texture.pcx",9,214);
   inv_add_slot_to_bag(bag,6,0,"leather_texture.pcx",70,214);
   inv_add_slot_to_bag(bag,7,0,"leather_texture.pcx",130,214);
   inv_add_slot_to_bag(bag,8,0,"leather_texture.pcx",190,214);
	
   // THIRD ROW OF INVENTORY BAG
	
   inv_add_slot_to_bag(bag,9,0,"leather_texture.pcx",9,278);
   inv_add_slot_to_bag(bag,10,0,"leather_texture.pcx",70,278);
   inv_add_slot_to_bag(bag,11,0,"leather_texture.pcx",130,278);
   inv_add_slot_to_bag(bag,12,0,"leather_texture.pcx",190,278);

   ...
 	
   set_on_click_callback("slot_was_clicked");
	
   ...
   
}



inventory.c
Code:
// 
// Inventory.c - programmed by Bret Truchan.  You are welcome to use this inventory
// system in the creation of commercial or free games.  You may not use it for any
// other purpose.
// 

/*


DOCUMENTATION

Table of Contents

   I. Introduction
  II. Essentials: inv_init() and inv_cleanup()
 III. Creating items for your inventory
  IV. Making your first bag
   V. Opening and Closing bags
  VI. Setting bag close and drag regions
 VII. Adding items to bags

VIII. Item Groups
  IX. Callbacks
  X. Other helpful functions


I. Introduction
---------------

Hello fellow programmer!  I hope that you can find the following inventory
system useful.  My main goal when making this inventory system was to decouple
the inventory system from the rest of the game code.  I also wanted to make it
as easy as possible to create and manage your inventory system.

This inventory has the following features:

1. Easy to use
2. Supports multiple bags
3. Handles the layering of bags for you
4. Supports callbacks for inventory events
5. Supports item "groups". (For example, gerbils can only be put in gerbil
slots.)

I modeled the inventory system after World of Warcraft.  One limitation to this
system is that slots in bags really need to be the same size.  I know how to 
fix this so, for example, your sword would show up huge in the sword slot but
small in a backpack slot, but I'll have to save that for a later release.



II. Essentials: inv_init() and inv_cleanup()
--------------------------------------------

Let's dive right in.  Creating your inventory is done in your lite-c code. 
You should not need to modify inventory.c.  Before anything else, include
inventory.c in your code, like so:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c" // <---- ADDED THIS

 void main()
 {
   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   // etc..

Add the inv_init(); function call to your main loop as shown above.  Because
inventory.c uses some low level C structures, you need to call inv_cleanup()
just before your game closes.


III. Creating items for your inventory
--------------------------------------

Let's skip ahead and create some images that will be needed for your
inventory.  If you have the demo for this inventory code, you can use my demo
images.

  pack.pcx - The is the background image of your inventory pack.
  slot_bg.pcx - The background image of an empty slot.
  item1.pcx - An icon of an item, such as a sword.  This should be the same
size as slot_bg.pcx.

Ok, back to items....

Items are strange.  You might think of an item like a "sword" or "gun". 
However, this inventory system is NOT trying to control how you manage items
for your game.  Although you might have a "sword" item in your inventory, the
structure that's passed around in the inventory code should NOT have
attributes such as "damage" or "weight".

Let's move ahead with an example of adding your first item - A pile of sand.
Maybe this pile of sand will go into your nephew's Christmas Stocking
because he ate all your friggin' cookies?!

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");


See that inv_create_item(...) statement?  inv_create_item() creates an abstract
item in your inventory system. Let's break it down:

 item_pointer = inv_create_item(item_id,group_id,floating_icon,inventory_icon);

Arguments:

 item_id - You make this up.  It can be anything that you want.  It doesn't affect the inventory engine.
 
 group_id - Later on, slots will also have a group id.  Items can only be put into slots with the right group id.

 floating_icon - The image used for the item while it's being dragged around the inventory system.

 inventory_icon - The image for displaying the item when the item is in a slot.

To reiterate, we introduced a new item into our inventory system.  We gave it an item id of 1, which really doesn't mean anything.  We gave it a group_id = 0, which means that the item can be placed into any slot having group_id=0.  We choose the same image "item1.pcx" for the icon used to "float" the item around in the inventory as well as the icon that represents the item in a slot.  That's good enough for now.  We'll keep moving forward..


IV. Making your first bag
-------------------------

There are a few terms that I loosly introduced above.  Your inventory may have multiple "bags".  Bags have multiple "slots", and slots may contain items.  Let's make our first bag.  Luckily, it's pretty easy:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;
 Bag* bag; // <---- added this line

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");
   bag = inv_create_bag(1,"pack.pcx");  // <---- added this line


Easy!  When you do this, the bag does not appear on the screen.  We'll handle that later.  For now, let's look closely at the
inv_create_bag() function:

   bag = inv_create_bag(bag_id,bag_image);

Arguments

 bag_id - You make this up.  It's not used within the inventory system, but it can be useful when handling callbacks.  We'll  
 discuss callbacks later on.

 bag_image - This should be an image of your open inventory bag.


Creating a bag is only half the battle.  Generally, you use the inv_add_slot_to_bag() function to add
a slot to your bag.  Here's the generic version:

  function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)

Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image

Here's a real world example of creating 4 slots to your bag:

  inv_add_slot_to_bag(bag,1,0,"slot_bg.pcx",9,38);
  inv_add_slot_to_bag(bag,2,0,"slot_bg.pcx",44,38);
  inv_add_slot_to_bag(bag,3,0,"slot_bg.pcx",78,38);
  inv_add_slot_to_bag(bag,4,0,"slot_bg.pcx",112,38);


V. Opening and Closing bags
---------------------------

Opening bags is easy:

  inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position);

That's it!  Here's use a real world example:

  inv_open_bag(bag, 100,100);

Closing your bag is even easier:

  inv_close_bag(bag);

We haven't added items to bags yet, but you'll see that it's very easy. When you open and close bags, the bags remember what items they contained.  You don't need to re-add the items.


VI. Setting bag close and drag regions
--------------------------------------

This inventory system allows you to drag bags around the screen and close them.  It's optional.  All you need to do is tell the inventory system where the drag region and close region are on the bag image.  Here's an example:

  inv_set_bag_drag_region(bag,5,3,128,18);
  inv_set_bag_close_region(bag,129,0,148,19);

The arguments are:

 function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
 function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)

Quick note:  For multiple bags, the inventory code automatically handles which bag should be "on top" if they overlap.


VII. Adding items to bags
-------------------------

Believe it or not, you're almost done.  Adding items to the inventory system can be done in two ways.  First, you can add an item directly to a bag.  Alternatively, you can create an item and immediately have it "float" (which means that the icon is visible and is being dragged by the mouse).

Adding an item directly to a bag:

  function inv_insert_item_into_bag(Bag* bag, Item* item)

For example:

  inv_insert_item_into_bag(bag,item_sand);

  (This function will return 1 if there was room in the bag for the item, otherwise 0.)

... OR "Floating" a new item:

  function inv_float_item(Item* item)

For example:

  function inv_float_item(item_sand);

That's it!


VIII. Item Groups
-----------------

Item groups are super easy.  Group_id 0 is special.  If you assign group_id = 0 to a slot, that slot can hold ANY
item.  Let's pretend that you want to make a weapon slot that can ONLY hold weapons.  When you create the sword item,
use the group_id = 4;  Then, when you create the sword slot, set its group_id = 4 too.  Done!


IX. Callbacks
-------------

If you need to know when certain events happen in the inventory system, you'll want to use the callbacks.  I'll explain with an example.  Let's say that you want to know whenever a bag is opened.  First, you need to define a function in your lite-c that will be called when a bag is open.  An open-bag callback function looks like:

a) open_bag_callback

  // put something like this in your lite-c

  function bag_was_opened(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_open_bag_callback() like so:

  set_on_open_bag_callback("bag_was_opened");

Whenever a bag is opened, your function bag_was_opened() will be called.  The bag_id of the opened bag will be passed into your function automatically.  Remember when we first created a bag and I said that the bag_id was useless?  I lied.  Here's where it comes into play.  You can tell which bag was opened by looking at the bag_id that's passed in to your callback function.

b) on_click_callback

This is most complicated callback.  It's triggered whenever someone clicks on a slot.  To use it, add something like this to your lite-c:

  function slot_was_clicked(int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id)
  {
    if (action == INV_ITEM_PLACED)
    {
       // item was placed in bag
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot  
       // removed_item_id is 0 and should be ignored
    }
    if (action == INV_ITEM_REMOVED)
    {
       // item was removed from bag  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is 0 and should be ignored 
       // removed_item_id is the item id that was removed from the slot
    }
    if (action == INV_ITEM_SWAPED)
    {
       // item was put in to a slot that already contained an item, so they were swapped  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot 
       // removed_item_id is the item id that was removed from the slot
    }
  }

And register your callback like:

  set_on_click_callback("slot_was_clicked");


c) on_bag_close_callback

This is just like on_bag_open_callback.  Here's an example:

  function bag_was_closed(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_close_bag_callback() like so:

  set_on_close_bag_callback("bag_was_closed");



X. Other helpful functions
--------------------------

 PANEL* inv_get_bag_panel_ptr(Bag* bag); // given a bag, return its panel pointer
 inv_is_bag_open(Bag* bag); // returns 1 if the bag is open, otherwise 0
 inv_get_open_bag_count(); // returns the number of open bags
 inv_is_floating(); // returns 1 if the player is floating an inventory item
 inv_is_item_in_bag(Bag* bag, Item* item); // returns 1 if the item is in the bag


*/





// ============================ BEGIN CODE =================================

#define new(type) malloc(sizeof(type##))
#define delete(object) free(object)

#define bag_layer 1
#define slot_layer 2
#define floating_item_layer 94

#define INV_ITEM_PLACED 1
#define INV_ITEM_SWAPPED 2
#define INV_ITEM_REMOVED 3

/* 
	struct Item

	The item structure holds a single item's information.  Items are intended to 
	track inventory icons only.  They're not really meant to manage an entire
	game's items.  For example, you would NOT use the item struct to hold values
	such as damage or defense rating for a sword.  The id in the item struct is
	intended to help associate these inventory based items with whatever item
	management is used in the game.  The id is set by the game developer to
	any arbitrary value.  The id is used in callback functions.
	
*/

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
	PANEL* slot_panel;
	
	int id;
	int group_id;
	int rel_x_pos;
	int rel_y_pos;
	int width;
	int height;
	
	STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
	int id;
	int is_open;
	
	int drag_region_top_left_x;
	int drag_region_top_left_y;
	int drag_region_bottom_right_x;
	int drag_region_bottom_right_y;

	int close_region_top_left_x;
	int close_region_top_left_y;
	int close_region_bottom_right_x;
	int close_region_bottom_right_y;
	
	PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;
     
} Bag;


// === Floating Item ===

typedef struct
{
	Item* item;
	PANEL* floating_item_panel;
	
} FloatingItem;


// Ugly linked list for keeping track of panels and associated slots

typedef struct SlotPanelAssoc
{
	PANEL* slot_panel;
	Slot* slot;
	struct SlotPanelAssoc* next;
	struct SlotPanelAssoc* prev;
	
} SlotPanelAssoc;


// Another ugly linked list for keeping track of z-order of open bags

typedef struct BagLayer
{
	Bag* bag;
	struct BagLayer* next;
	struct BagLayer* prev;
	
} BagLayer;


// Global variables

SlotPanelAssoc* slot_panel_assoc;
BagLayer* bag_layer_node;
 
FloatingItem* global_floating_item_ptr;

int inv_floating_flag;
int inv_open_bag_count; // The number of open bags
int inv_item_count; // index used for the inv_items_array
int inv_bag_count;  // index used for the inv_bags_array

Item* inv_items_array[5000];  // Global array to hold item pointers.  Used by cleanup script only.
Bag* inv_bags_array[100]; // Again, store all created bags in this array so we can properly deallocate them later.


// =============== FUNCTIONS =============================================================


// function prototypes

function inv_close_bag(Bag*);
function _inv_do_float(FloatingItem*);
function _inv_drag_bag(Bag*, int drag_offset_x, int drag_offset_y);

function addBagLayer(Bag*);
function removeBagLayer(Bag*);
function reorderBagLayers();
function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel);
function removeSlotPanelAssoc(Slot* slot);

function getSlotPtrForPanelPtr(PANEL* panel_ptr);
function getBagPtrForPanelPtr(PANEL* panel_ptr);


// Callback function prototypes

void on_click_callback_function_ptr(int inv_action, int bag_id, int slot_id, int placed_item_id, int removed_item_id);
void on_float_end_callback_function_ptr();
void on_close_bag_callback_function_ptr(int bag_id);
void on_open_bag_callback_function_ptr(int bag_id);




// --------------- Inventory Function -----------------------------------
 
 
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  

}

/*

function slot_was_clicked(int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id) // ADDED THIS*****************************************************
{
   if (occurrence == INV_ITEM_PLACED)
   {
	   // item was placed in bag
   	// bag_id is the id of the bag where the item was placed
   	// slot_id is the id of the slot where the item was placed  
   	// placed_item_id is the item id that was placed into the slot  
   	// removed_item_id is 0 and should be ignored
      
   	if (bag_id == 1)
   	{
   		if (slot_id == 0)
   		{
   			if (placed_item_id == 2)
   			{
   				active_sword = ent_create ("sword.mdl", player.x, attach_weapon);
         	}
         	else
         	{
         		ent_remove(active_sword);
	      	}
	   	}
		}   
	}
}
*/
 
function bagOnClick(PANEL* panel_ptr)
{
	Bag* bag;
	
	bag = getBagPtrForPanelPtr(panel_ptr);
	
	// Check to see if the player is dragging the panel
	
	if (bag->drag_region_top_left_x != bag->drag_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->drag_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->drag_region_top_left_x + (bag->drag_region_bottom_right_x - bag->drag_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->drag_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->drag_region_top_left_y + (bag->drag_region_bottom_right_y - bag->drag_region_top_left_y))))
		{
			_inv_drag_bag(bag,mouse_pos.x - bag->bag_panel->pos_x, mouse_pos.y - bag->bag_panel->pos_y);
		}
	}
	
	if (bag->close_region_top_left_x != bag->close_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->close_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->close_region_top_left_x + (bag->close_region_bottom_right_x - bag->close_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->close_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->close_region_top_left_y + (bag->close_region_bottom_right_y - bag->close_region_top_left_y))))
		{
			inv_close_bag(bag);
			return(0);
		}
	}

	// Bring bag to the front

	removeBagLayer(bag);		
	addBagLayer(bag);		

	reorderBagLayers();

}

function _inv_drag_bag(Bag* bag, int drag_offset_x, int drag_offset_y)
{
	int i;
		
	while(mouse_left)
	{
		
		vec_set(mouse_pos,mouse_cursor);
					
		// Move bag
		bag->bag_panel->pos_x = mouse_pos.x - drag_offset_x;
		bag->bag_panel->pos_y = mouse_pos.y - drag_offset_y;
		
		// Move all slots
		for (i=0; i < bag->_slot_count; i++)
		{
			bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + bag->bag_panel->pos_x;
			bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + bag->bag_panel->pos_y;
		}		
		
		wait(1);
	}
}

function slotOnClick(PANEL* clicked_panel) // KEY TO SOLVING PROBLEM?????????????????????????????????????????????????????????????????????????????????
{

	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	// player clicked on item in inventory while not floating an item
	
	diag("test1");
	
	if (global_floating_item_ptr->item == NULL)
	{
		diag("test2");

		if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
		{
			
			diag("\ngrab started\n");
			
			// optionally callback with action, bag_id, slot_id, item_id
			if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);


			// Create the floating panel
			
			global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
			
			// Set the item and panel image of the floating item structure.  This effectively "floats"
			// the item that was stored in the inventory slot.
			
			global_floating_item_ptr->item = clicked_slot->item;
			global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
			global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
			
			// Set the item pointer of the clicked on slot to NULL
			
			clicked_slot->item = NULL;
			
			// Restore inventory slot image to be the default background image
			
			clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			

			inv_floating_flag = 1;
			_inv_do_float(global_floating_item_ptr);
			

		}
	}
	else
	{
		diag("test3");

		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
				
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
	
}

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
		
}



function _inv_do_float(FloatingItem* floating_item)
{
	proc_mode = PROC_LATE;
		
	mouse_mode = 4;
	mouse_pointer = 1;
	 
	while(inv_floating_flag == 1)
	{
		floating_item->floating_item_panel.pos_x = mouse_pos.x + 10;
		floating_item->floating_item_panel.pos_y = mouse_pos.y + 10;
		wait(1);		
	}

	// optionally do a callback when floating ends
		
	if (on_float_end_callback_function_ptr) on_float_end_callback_function_ptr();

}

function inv_float_item(Item* item)
{
	
	global_floating_item_ptr->item = item;
	global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
	global_floating_item_ptr->floating_item_panel->bmap = bmap_create(item->floating_icon);
	
	global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
	
	inv_floating_flag = 1; // set global floating flag
	
	_inv_do_float(global_floating_item_ptr);
	
	return global_floating_item_ptr;
}


function inv_create_bag(int bag_id, STRING* image_name)
{
	Bag* bag;
	bag = new(Bag);
	
	bag->image_name = image_name;
	bag->id = bag_id;
	
	// Initialize slot_count to 0
	bag->_slot_count = 0;
	bag->is_open = 0;
	
	// Add bag to global array for cleanup purposes

	inv_bags_array[inv_bag_count] = bag;
	inv_bag_count++;
	
	return bag;
}

function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->drag_region_top_left_x = top_left_x;	
	bag->drag_region_top_left_y = top_left_y;	
	bag->drag_region_bottom_right_x = bottom_right_x;	
	bag->drag_region_bottom_right_y = bottom_right_y;
}

function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->close_region_top_left_x = top_left_x;	
	bag->close_region_top_left_y = top_left_y;	
	bag->close_region_bottom_right_x = bottom_right_x;	
	bag->close_region_bottom_right_y = bottom_right_y;
}

function inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position)
{
	bag->bag_panel = pan_create("",bag_layer_node);
	bag->bag_panel->bmap = bmap_create(bag->image_name);
	bag->bag_panel->event = bagOnClick;

	bag->is_open = 1;
	
	int i;
	
	// Add slots
	
	for (i=0; i < bag->_slot_count; i++)
	{
		
		bag->slots[i]->slot_panel = pan_create("",slot_layer);
		
		if (bag->slots[i]->item == NULL)
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->background_image);
		}
		else
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->item->inventory_icon);
		}
		
		bag->slots[i]->slot_panel->event = slotOnClick;
		bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + panel_x_position;
		bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + panel_y_position;
		
		// Make the new slot panel visible
		bag->slots[i]->slot_panel->flags |= VISIBLE;
		
		// Add this panel and slot to the linked list
		addSlotPanelAssoc(bag->slots[i],bag->slots[i]->slot_panel);
	}
	
	bag->bag_panel->pos_x = panel_x_position;
	bag->bag_panel->pos_y = panel_y_position;
		
	bag->bag_panel->flags |= VISIBLE;
	
	if (on_open_bag_callback_function_ptr) on_open_bag_callback_function_ptr(bag->id);
	
	inv_open_bag_count++;
	
	// Add the pointer to this bag to the front of a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	addBagLayer(bag);
	reorderBagLayers();
	
}

function inv_close_bag(Bag* bag)
{
	if (bag == NULL) 
	{
		diag("\nWARNING: inv_close_bag called with argument NULL\n");
		return 0;
	}

	bag->is_open = 0;
	
	int i;
	
	for (i=0; i < bag->_slot_count; i++)
	{
		// Remove each slot panel
		pan_remove(bag->slots[i]->slot_panel);
		
		// Remove the slot from the associative array
		removeSlotPanelAssoc(bag->slots[i]);
	}

	// remove bag panel
	
	pan_remove(bag->bag_panel);
	
	if (on_close_bag_callback_function_ptr) on_close_bag_callback_function_ptr(bag->id);
		
	inv_open_bag_count--;
	
	// Remove the pointer to this bag from a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	
	removeBagLayer(bag);		
}

//***********************************************************************************************************************************************************************

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

function inv_insert_item_into_bag(Bag* bag, Item* item)  // COULD THIS SOLVE THE PROBLEM?????????????????????????????????????????????????????????????????????
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				/*
				else // ADDED BY RUBEN
				if(bag->slots[i]->group_id == 1)
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
				// END OF ADDED BY RUBEN
				*/
			}
		}
	}
	
	return 0;
}

function inv_cleanup()
{
	diag("\nStarting inventory cleanup\n");
	
	int i;
	int j;
	
	// Clean up items
	
	Item* item;
	
	for(i=0;i<inv_item_count;i++)
	{
		diag("\n   * cleaning up inventory item");
		item = inv_items_array[i];
		
		if (item != NULL)
		{
			free(item->floating_icon);
			free(item->inventory_icon);
			free(item);
			diag(" - success");
		}
	}
	
	// Clean up bags
	
	Bag* bag;
	
	for (i=0; i<inv_bag_count; i++)
	{
		diag("\n   * cleaning up bag");		
		bag = inv_bags_array[i];
		
		if (bag != NULL)
		{
			// Clean up slots in bag

			for (j=0; j < bag->_slot_count; j++)
			{
				diag("\n     - cleaning up slot");
				free(bag->slots[j]->background_image);
				free(bag->slots[j]);
			}			
			
			free(bag->image_name);
			free(bag);
		}		
	}
	
	free(global_floating_item_ptr);
	
	diag("\nCompleted inventory cleanup\n");
	
}


// ------------- Helpful functions --------------

function inv_get_bag_panel_ptr(Bag* bag)
{
	return bag->bag_panel;	
}

function inv_is_bag_open(Bag* bag)
{
	if (bag == NULL) return 0;
	return bag->is_open;
}

function inv_get_open_bag_count()
{
	return inv_open_bag_count;
}

function inv_is_floating()
{
	return inv_floating_flag;
}

function inv_is_item_in_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i]->item == item)
		{
			return 1;
		}
	}
	
	return 0;
}


// ------------- Create Callback Functions ---------

function set_on_click_callback(STRING* function_name) { on_click_callback_function_ptr = engine_getscript(function_name); } //******************************************************
function set_on_float_end_callback(STRING* function_name) { on_float_end_callback_function_ptr = engine_getscript(function_name); }
function set_on_close_bag_callback(STRING* function_name) { on_close_bag_callback_function_ptr = engine_getscript(function_name); }
function set_on_open_bag_callback(STRING* function_name) { on_open_bag_callback_function_ptr = engine_getscript(function_name); }



// --------------- linked-list functions --------------------------------

// ** list functions for managing bag z order

function addBagLayer(Bag* bag)
{
	if(bag_layer_node == NULL)
	{
		bag_layer_node = new(BagLayer);
		bag_layer_node->bag = bag;

		bag_layer_node->next = NULL;
		bag_layer_node->prev = NULL;
	}
	else
	{
		// Create a new BagLayer struct and put it at the beginning of the list
		BagLayer* new_bag_layer_node = new(BagLayer);
		new_bag_layer_node->bag = bag;
				
		bag_layer_node->prev = new_bag_layer_node;
		new_bag_layer_node->next = bag_layer_node;
		new_bag_layer_node->prev = NULL;
		
		bag_layer_node = new_bag_layer_node;
	}
	
}

function removeBagLayer(Bag* bag)
{
	int first_node = 1;
	
	BagLayer* iterator = bag_layer_node;
	
	while(iterator != NULL)
	{
		if (iterator->bag == bag)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;
			
			if (first_node) bag_layer_node = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function reorderBagLayers()
{
	int new_bag_layer = 90;
	int sanity_check = 0;
	int i;
	
	BagLayer* iterator = bag_layer_node;
	Bag* bag;
		
	while(iterator != NULL)
	{
		// Chage bag layer
		bag = iterator->bag;		
		layer_sort(bag->bag_panel,new_bag_layer);
		
		// Change bag's slot layers
		for (i=0; i < bag->_slot_count; i++)
		{
			layer_sort(bag->slots[i]->slot_panel,new_bag_layer + 1);
		}		
		
		new_bag_layer -= 3;
		iterator = iterator->next;
		
		sanity_check++;
		if (sanity_check > 100) 
		{
			diag("ERROR: reorderBagLayers has run amok!");
			break;
		}
	}
	
}

// ** list functions for storing associations between panels and slots

function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel)
{
	if(slot_panel_assoc == NULL)
	{
		slot_panel_assoc = new(SlotPanelAssoc);
		slot_panel_assoc->slot_panel = slot_panel;
		slot_panel_assoc->slot = slot;

		slot_panel_assoc->next = NULL;
		slot_panel_assoc->prev = NULL;
		
	}
	else
	{
		// Create a new slot_panel_assoc struct and put it at the beginning of the list
		SlotPanelAssoc* new_slot_panel_assoc = new(SlotPanelAssoc);
		new_slot_panel_assoc->slot_panel = slot_panel;
		new_slot_panel_assoc->slot = slot;
				
		slot_panel_assoc->prev = new_slot_panel_assoc;
		new_slot_panel_assoc->next = slot_panel_assoc;
		new_slot_panel_assoc->prev = NULL;
		
		slot_panel_assoc = new_slot_panel_assoc;
	}
}

function removeSlotPanelAssoc(Slot* slot)
{
	int first_node = 1;

	SlotPanelAssoc* iterator = slot_panel_assoc;
	
	while(iterator != NULL)
	{
		if (iterator->slot == slot)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;

			if (first_node) slot_panel_assoc = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function getSlotPtrForPanelPtr(PANEL* panel_ptr)
{
	SlotPanelAssoc* iterator = slot_panel_assoc;

	if (iterator == NULL) 
	{
		diag("\nWARNING: getStructForPanelPtr returned NULL.");
	}
	
	while(iterator != NULL)
	{
		if (iterator.slot_panel == panel_ptr)
		{
			return(iterator.slot);
		}
		iterator = iterator->next;
	}
	
	return NULL;
}

/* 

	getBagPtrForPanelPtr(PANEL* panel_ptr)
 
	Given a panel pointer, return a pointer to the bag having that panel.
	In this case, we're lucky because the bags are all stored in the
	global inv_bags_array.  Why not store the slots in a similar array? --
	Because they're constantly created and destroyed.
	
*/

function getBagPtrForPanelPtr(PANEL* panel_ptr)
{
	int i;
	Bag* bag;
	
	for (i=0;i<inv_bag_count;i++)
	{
		bag = inv_bags_array[i];
		
		if (bag->bag_panel == panel_ptr)
		{
			return bag;
		}	
	}
	
	return NULL;
	
}



My program can compile without syntax errors, but when I place the sword in the active weapon slot of the inventory bag, the player is still not being armed with a sword in its hand.

Am I using the callback function incorrectly, or forgetting a step?
Posted By: txesmi

Re: Access variable from other program? - 01/04/14 21:35

Ok, I played a bit with the code and the very first thing I found is a bug xP

Modify the function 'inv_init' to solve it:
Code:
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  
	
	on_click_callback_function_ptr = NULL;
	on_float_end_callback_function_ptr = NULL;
	on_close_bag_callback_function_ptr = NULL;
	on_open_bag_callback_function_ptr = NULL;
}



Another thing I found is that you can't insert items into an inventory that is not opened. Modify the functions 'inv_add_slot_to_bag' and 'inv_insert_item_into_bag' to solve it. I also added a slot_on_click callback to 'inv_insert_item_into_bag' that is really needed.

Code:
function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
	new_slot->slot_panel = NULL;	// <---- NEW LINE
	
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

function inv_insert_item_into_bag ( Bag* bag, Item* item )
{
	int i;
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;
					if ( bag->slots[i]->slot_panel )				
						bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,bag->id,bag->slots[i]->id,item->id,NULL);
					return 1;
				}
			}
		}
	}
	
	return 0;
}



These little changes let you run the following code without errors and you will be able to change the active weapon using a slot of the inventory:
Code:
#include <acknex.h>
#include "inventory.c"

#define PRAGMA_PATH "%EXE_DIR%\\templates\\sounds"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\images"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\models"

#define MAIN_BAG_ID        1
#define ACTIV_WPN_SLOT_ID  0

#define SNIPERGUN          0
#define SHOTGUN            1
#define MACHINEGUN         2

SOUND *sndReload = "reload.wav";

ENTITY *active_weapon = NULL;

function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
				active_weapon = NULL;
			}
		}   
   }
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				snd_play ( sndReload, 100, 0 );
				switch ( placed_item_id )
				{
					case SNIPERGUN:  active_weapon = ent_create ( "snipergun.mdl", nullvector, NULL );  break;
					case SHOTGUN:    active_weapon = ent_create ( "shotgun.mdl", nullvector, NULL );    break;
					case MACHINEGUN: active_weapon = ent_create ( "machinegun.mdl", nullvector, NULL ); break;
				}
			}
		}   
	}
}

function main()
{
	mouse_mode = 4;
   inv_init();
   wait(1);
	level_load ( "" );
	camera->x = -150;
   Item *gun1 = inv_create_item ( SNIPERGUN, 1, "icon2.pcx", "icon2.pcx" );
   Item *gun2 = inv_create_item ( SHOTGUN, 1, "icon3.pcx", "icon3.pcx" );
   Item *gun3 = inv_create_item ( MACHINEGUN, 1, "icon4.pcx", "icon4.pcx" );

   Bag *bag = inv_create_bag ( MAIN_BAG_ID,"bluebar.pcx");
   inv_add_slot_to_bag ( bag, ACTIV_WPN_SLOT_ID, 1, "flash2.tga", 0, 0 );
   inv_add_slot_to_bag(bag,1,0,"flash2.tga",0,120);
   inv_add_slot_to_bag(bag,2,0,"flash2.tga",0,180);
   inv_add_slot_to_bag(bag,3,0,"flash2.tga",0,240);
   
   set_on_click_callback ( "slot_was_clicked" );
   
   inv_insert_item_into_bag ( bag, gun1 );
   inv_insert_item_into_bag ( bag, gun2 );
   inv_insert_item_into_bag ( bag, gun3 );
   
   inv_open_bag ( bag, 0, 0 );
   
   while ( !key_esc )
   {
   	if ( active_weapon != NULL )
   		active_weapon->pan += 5*time_step;
   	wait(1);
	}
   
   sys_exit ( NULL );
}



Salud!
Posted By: Ruben

Re: Access variable from other program? - 01/05/14 01:02

Thank you for your code changes txesmi, but I am still not able to arm my player with a sword when I place a sword image in the active weapon slot.

I made the changes to inventory.c as you specified.

Here is the code I currently have after making some changes:

OrcStronghold.c
Code:
#include <acknex.h>
#include <default.c>
#include "inventory.c"

...

#define MAIN_BAG_ID        1
#define ACTIV_WPN_SLOT_ID  0
#define SWORD_ID           2

#define SWORD              0
#define MACE               1
#define SHIELD             2
#define APPLE              3
#define GOLD_COINS         4

...

Item *item_shield;
Item *item_apple;
Item *item_sword;
Item *item_mace;
Item *item_gold;

...

ENTITY *active_weapon = NULL;
ENTITY* mace;

Bag* bag;

...

action attach_weapon() 
{
	set(my,PASSABLE);
	proc_mode = PROC_LATE;
	
	while (you != NULL) 
	{
		vec_for_vertex(temp.x,you,997); //hand palm base: Vector # 987
		vec_for_vertex(temp2.x,you,968); //hand palm tip: Vector # 982
		vec_set(my.x,temp.x);
		vec_diff(temp.x,temp2.x,temp.x);
		vec_to_angle(my.pan,temp.x); // ERROR "'pan' is not a member of 'VECTOR'
		vec_set(my.pan,my.pan);
		wait(1);
	}
}

void addApple()
{
	inv_insert_item_into_bag(bag,item_apple); 
}

void addShield()
{
	inv_insert_item_into_bag(bag,item_shield);
}

void addSword()
{
	inv_insert_item_into_bag(bag,item_sword);
}

void addGold()
{
	inv_insert_item_into_bag(bag,item_gold);
}

...

// USED TO OPEN INVENTORY BAG BY CLICKING "i" KEY
//    switch to toggle inventory:
void toggleInventory()
{	
	// put some comparisons here:
	// f.e. if we are dead, don't allow to toggle inventory:
	if(player.HEALTH <= 0)
	{ 
		return; 
	}
	// toggle var:
	invOpen += 1;
	invOpen %= 2;
	
	// if we've opened the inventory:
	if(invOpen == 1)
	{
		// show the mouse pointer:
		
		change_mouse_mode();
		mouse_mode = 1;
		
		// PUT IN CODE FOR INVENTORY GUI
		
	   inv_open_bag ( bag, 0, 0 );  // OPEN INVENTORY BAG CODE
	}
	else
	{
		
		mouse_mode = 0;
	   inv_close_bag(bag);

   }
}

...

function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
				active_weapon = NULL;
			}
		}   
   }
   if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
	if (bag_id == MAIN_BAG_ID)
	{
		if (slot_id == ACTIV_WPN_SLOT_ID)
		{
			switch ( placed_item_id )
			{
				case SWORD:  active_weapon = ent_create ( "sword.mdl", my.x, attach_weapon );  break;
				case MACE:   active_weapon = ent_create ( "mace.mdl", my.x, attach_weapon );    break;
			}
		}
	}   
   }
}

function main()
{
	
   ...

   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   item_shield = inv_create_item(SHIELD,0,"shield.pcx","shield.pcx");
   item_apple = inv_create_item(APPLE,0,"apple.pcx","apple.pcx");
   item_sword = inv_create_item(SWORD,1,"steel_sword.pcx","steel_sword.pcx");
   item_mace = inv_create_item(MACE,1,"mace.pcx","mace.pcx");
   item_gold = inv_create_item(GOLD_COINS,0,"gold_coins.pcx","gold_coins.pcx");

   bag = inv_create_bag(MAIN_BAG_ID,"leather_seam.pcx");  // <---- added this line
   
   // START OF INVENTORY BAG
   
   // ACTIVE ITEM SLOT
   
   inv_add_slot_to_bag(bag,0,1,"leather_texture.pcx",9,60); // 3RD VALUE "1", ONLY ITEMS WITH THIS VALUE CAN BE INSERTED INTO THIS SLOT.

   // EACH ROW OF INVENTORY BAG IS SPACED OUT BY 64 HEIGHT
   // FIRST ROW OF INVENTORY BAG

   inv_add_slot_to_bag(bag,1,0,"leather_texture.pcx",9,150);
	 
   inv_add_slot_to_bag(bag,2,0,"leather_texture.pcx",70,150);

   inv_add_slot_to_bag(bag,3,0,"leather_texture.pcx",130,150);
	 
   inv_add_slot_to_bag(bag,4,0,"leather_texture.pcx",190,150);
	
   // SECOND ROW OF INVENTORY BAG
		
   inv_add_slot_to_bag(bag,5,0,"leather_texture.pcx",9,214);

   inv_add_slot_to_bag(bag,6,0,"leather_texture.pcx",70,214);
	
   inv_add_slot_to_bag(bag,7,0,"leather_texture.pcx",130,214);
	
   inv_add_slot_to_bag(bag,8,0,"leather_texture.pcx",190,214);
	
   // THIRD ROW OF INVENTORY BAG
	
   inv_add_slot_to_bag(bag,9,0,"leather_texture.pcx",9,278);
	
   inv_add_slot_to_bag(bag,10,0,"leather_texture.pcx",70,278);
    
  inv_add_slot_to_bag(bag,11,0,"leather_texture.pcx",130,278);
	
  inv_add_slot_to_bag(bag,12,0,"leather_texture.pcx",190,278);

   inv_set_bag_drag_region(bag,5,3,128,18);
   inv_set_bag_close_region(bag,129,0,148,19);
 	
   set_on_click_callback("slot_was_clicked");
 	
   // USED FOR TESTING INVENTORY BAG FUNCTIONALITY
 	
   on_1 = addApple;
   on_2 = addShield;
   on_3 = addSword;
   on_4 = addGold;
 		
   while ( !key_esc )
   {
   	if ( active_weapon != NULL )
   		active_weapon->pan += 5*time_step;
   		
   	mouse_pos.x = mouse_cursor.x;
        mouse_pos.y = mouse_cursor.y;
      
        // if we've enabled the mouse:
        if(mouse_mode > 0)
        {
      	   // move it's position with a cursor:
      	   vec_set(mouse_pos.x, mouse_cursor.x);
        }
   		
   	wait(1);
   }
	
   sys_exit ( NULL );
}



I am still getting the same result with this code, although I am not getting syntax errors when I compile. Am I doing something wrong?
Posted By: Ruben

Re: Access variable from other program? - 01/05/14 09:18

When I press the "i" button to open my inventory bag, and then I press the "3" button to insert a sword into my inventory bag, which also places the sword in the active weapon slot (since I did not insert any other weapons in the inventory bag beforehand), I get a pop-up box with this error:

Script crash in slot_was_clicked

I press the OK button, and the picture of the sword shows up in the active weapon slot of the inventory bag, but when I press the "i" key again to close the inventory bag, a sword is not being equipped in my player's hand.
Posted By: txesmi

Re: Access variable from other program? - 01/05/14 09:42

Code:
case SWORD:  active_weapon = ent_create ( "sword.mdl", my.x, attach_weapon );  break;



'me'/'my' is not a valid pointer in a function called from the inventory engine.

Originally Posted By: Manual

my
me
Pointer to the entity that the current function is executed from or assigned to. Is valid for the whole function and for all functions called from it, and is preserved during wait(). The pointer is invalid if the function was not executed by an entity, e.g. by a key event or called from the main() function.


Code:
action attach_weapon() 
{
...
while (you != NULL)



'you' is not a valid pointer in an action of an entity created by a function called from the inventory engine.

Originally Posted By: Manual

your
you
Pointer to a second entity. Is preserved in functions during wait(), but modified by many functions. At the start of an entity function, you is the pointer to the creating entity (if any), otherwise NULL.


Use 'player' pointer instead.
Salud!
Posted By: pegamode

Re: Access variable from other program? - 01/05/14 10:21

Hey there,

I just saw this thread and noticed that you are using the inventory system by Bret Truchan. I used this one a while ago and it worked pretty well, but there were also some bugs in it that I had to fix as far as I remember.
So if you run into any problems you can PM me as I might remember what I modified.

Regards,
Pegamode.
Posted By: Ruben

Re: Access variable from other program? - 01/05/14 10:52

Thank you txesmi! It works! I changed all the instances of "my" to "player", and it works! Thank you again. :-D

One problem though. I separated my WED 3D environment into different WED files, in order to separate out the memory, instead of having all the memory in one WED file. When my player walks into a door for instance, that activates a new WED file that the player passes into.

My problem is that the player loses the weapon that it was carrying in its hand before it ran into the door that activated the new WED file.

When I press the "i" key to open the inventory bag after entering the new WED level, I see that my current weapon image from the last WED level is still saved in the active weapon slot, but my player is not armed with that weapon in its hand anymore. In order to arm my player with the weapon again, I have to open the inventory bag, click on the weapon in the active weapon slot, and repeat placing it back into the active weapon slot, in order to arm my player with the same weapon again.

Is there a way to save the weapon to still be in the player's hand as the player passes from one WED level to the next?
Posted By: Ruben

Re: Access variable from other program? - 01/05/14 10:55

Thank you pegamode. :-)
Posted By: Ruben

Re: Access variable from other program? - 01/05/14 11:56

Never mind. I figured out the solution to my last problem. Thank you all so much for your advice! :-)
Posted By: txesmi

Re: Access variable from other program? - 01/05/14 12:17

Glad to help ;D

Anyway I wrote a function to run the slot_on_click callback with the parameters of the item allocated in a certain slot of a bag if exists.

Code:
function inv_run_slot_callback ( Bag *bag, var slot_id )
{
	if ( !on_click_callback_function_ptr )
		return 0;
	
	int i = 0;
	for ( ; i<bag->_slot_count; i++ )
	{
		Slot *slot = bag->slots[i];
		if ( slot->id != slot_id )
			continue;
		Item *item = slot->item;
		if ( !item )
			return 0;
		on_click_callback_function_ptr ( INV_ITEM_PLACED, bag->id, slot->id, item->id, NULL );
		return 1;
	}
	return 0;
}



Call it when your 'player' pointer is properly filled after level loading.
Salud!
Posted By: Ruben

Re: Access variable from other program? - 01/08/14 03:49

Hello txesmi.

Sorry if I seem confused, but is the inv_run_slot_callback() function designed to load the weapon into the player's hand when the player enters a new WED level?
Posted By: Ruben

Dropping items from inventory bag - 01/08/14 04:08

Hello Fellow Programmers,

So, I am using an open source inventory.c program that allows me to create an inventory bag for the player. I finally have in my program the ability for the player to pick up an item off the ground (left-click on item), and the item gets added to the player's inventory bag.

I am now trying to figure out the reverse: How to drop items from the player's inventory. My goal is to make it to where the player can click an item in her/his inventory bag (to where the item gets attached to the mouse cursor), the player moves the item outside the inventory bag with the mouse cursor, and once the player clicks the left mouse button at this point, the item gets dropped from the player's inventory and ends up lying on the ground, next to the player's feet.

Does anyone know what type of "if" statement I would use to test whether the player clicked an inventory item outside the inventory bag (from there I can probably program it to where the item can be removed from the inventory bag, and placed on the ground close to the player)?

Does anyone know what I should test for in the "if" statement to make this happen? For example:

(1) PLAYER CLICKS ITEM IN INVENTORY BAG.
(2) ITEM GETS ATTACHED TO MOUSE CURSOR.
(3) PLAYER MOVES ITEM WITH MOUSE CURSOR TO OUTSIDE INVENTORY
BAG.
(4) PLAYER LEFT CLICKS
Code:
if ("PLAYER LEFT-CLICKED ITEM OUTSIDE OF INVENTORY BAG")
{
   ITEM GETS DELETED FROM INVENTORY.
   MODEL OF DROPPED ITEM GETS CREATED CLOSE TO THE PLAYER'S 
      FEET.
}


Does anyone know what kind of condition in the IF statement might make functionality like this work?

Here is the code of the public domain inventory.c , with a few minor tweaks to take out some bugs:

inventory.c
Code:
// 
// Inventory.c - programmed by Bret Truchan.  You are welcome to use this inventory
// system in the creation of commercial or free games.  You may not use it for any
// other purpose.
// 

/*


DOCUMENTATION

Table of Contents

   I. Introduction
  II. Essentials: inv_init() and inv_cleanup()
 III. Creating items for your inventory
  IV. Making your first bag
   V. Opening and Closing bags
  VI. Setting bag close and drag regions
 VII. Adding items to bags

VIII. Item Groups
  IX. Callbacks
  X. Other helpful functions


I. Introduction
---------------

Hello fellow programmer!  I hope that you can find the following inventory
system useful.  My main goal when making this inventory system was to decouple
the inventory system from the rest of the game code.  I also wanted to make it
as easy as possible to create and manage your inventory system.

This inventory has the following features:

1. Easy to use
2. Supports multiple bags
3. Handles the layering of bags for you
4. Supports callbacks for inventory events
5. Supports item "groups". (For example, gerbils can only be put in gerbil
slots.)

I modeled the inventory system after World of Warcraft.  One limitation to this
system is that slots in bags really need to be the same size.  I know how to 
fix this so, for example, your sword would show up huge in the sword slot but
small in a backpack slot, but I'll have to save that for a later release.



II. Essentials: inv_init() and inv_cleanup()
--------------------------------------------

Let's dive right in.  Creating your inventory is done in your lite-c code. 
You should not need to modify inventory.c.  Before anything else, include
inventory.c in your code, like so:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c" // <---- ADDED THIS

 void main()
 {
   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   // etc..

Add the inv_init(); function call to your main loop as shown above.  Because
inventory.c uses some low level C structures, you need to call inv_cleanup()
just before your game closes.


III. Creating items for your inventory
--------------------------------------

Let's skip ahead and create some images that will be needed for your
inventory.  If you have the demo for this inventory code, you can use my demo
images.

  pack.pcx - The is the background image of your inventory pack.
  slot_bg.pcx - The background image of an empty slot.
  item1.pcx - An icon of an item, such as a sword.  This should be the same
size as slot_bg.pcx.

Ok, back to items....

Items are strange.  You might think of an item like a "sword" or "gun". 
However, this inventory system is NOT trying to control how you manage items
for your game.  Although you might have a "sword" item in your inventory, the
structure that's passed around in the inventory code should NOT have
attributes such as "damage" or "weight".

Let's move ahead with an example of adding your first item - A pile of sand.
Maybe this pile of sand will go into your nephew's Christmas Stocking
because he ate all your friggin' cookies?!

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");


See that inv_create_item(...) statement?  inv_create_item() creates an abstract
item in your inventory system. Let's break it down:

 item_pointer = inv_create_item(item_id,group_id,floating_icon,inventory_icon);

Arguments:

 item_id - You make this up.  It can be anything that you want.  It doesn't affect the inventory engine.
 
 group_id - Later on, slots will also have a group id.  Items can only be put into slots with the right group id.

 floating_icon - The image used for the item while it's being dragged around the inventory system.

 inventory_icon - The image for displaying the item when the item is in a slot.

To reiterate, we introduced a new item into our inventory system.  We gave it an item id of 1, which really doesn't mean anything.  We gave it a group_id = 0, which means that the item can be placed into any slot having group_id=0.  We choose the same image "item1.pcx" for the icon used to "float" the item around in the inventory as well as the icon that represents the item in a slot.  That's good enough for now.  We'll keep moving forward..


IV. Making your first bag
-------------------------

There are a few terms that I loosly introduced above.  Your inventory may have multiple "bags".  Bags have multiple "slots", and slots may contain items.  Let's make our first bag.  Luckily, it's pretty easy:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;
 Bag* bag; // <---- added this line

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");
   bag = inv_create_bag(1,"pack.pcx");  // <---- added this line


Easy!  When you do this, the bag does not appear on the screen.  We'll handle that later.  For now, let's look closely at the
inv_create_bag() function:

   bag = inv_create_bag(bag_id,bag_image);

Arguments

 bag_id - You make this up.  It's not used within the inventory system, but it can be useful when handling callbacks.  We'll  
 discuss callbacks later on.

 bag_image - This should be an image of your open inventory bag.


Creating a bag is only half the battle.  Generally, you use the inv_add_slot_to_bag() function to add
a slot to your bag.  Here's the generic version:

  function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)

Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image

Here's a real world example of creating 4 slots to your bag:

  inv_add_slot_to_bag(bag,1,0,"slot_bg.pcx",9,38);
  inv_add_slot_to_bag(bag,2,0,"slot_bg.pcx",44,38);
  inv_add_slot_to_bag(bag,3,0,"slot_bg.pcx",78,38);
  inv_add_slot_to_bag(bag,4,0,"slot_bg.pcx",112,38);


V. Opening and Closing bags
---------------------------

Opening bags is easy:

  inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position);

That's it!  Here's use a real world example:

  inv_open_bag(bag, 100,100);

Closing your bag is even easier:

  inv_close_bag(bag);

We haven't added items to bags yet, but you'll see that it's very easy. When you open and close bags, the bags remember what items they contained.  You don't need to re-add the items.


VI. Setting bag close and drag regions
--------------------------------------

This inventory system allows you to drag bags around the screen and close them.  It's optional.  All you need to do is tell the inventory system where the drag region and close region are on the bag image.  Here's an example:

  inv_set_bag_drag_region(bag,5,3,128,18);
  inv_set_bag_close_region(bag,129,0,148,19);

The arguments are:

 function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
 function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)

Quick note:  For multiple bags, the inventory code automatically handles which bag should be "on top" if they overlap.


VII. Adding items to bags
-------------------------

Believe it or not, you're almost done.  Adding items to the inventory system can be done in two ways.  First, you can add an item directly to a bag.  Alternatively, you can create an item and immediately have it "float" (which means that the icon is visible and is being dragged by the mouse).

Adding an item directly to a bag:

  function inv_insert_item_into_bag(Bag* bag, Item* item)

For example:

  inv_insert_item_into_bag(bag,item_sand);

  (This function will return 1 if there was room in the bag for the item, otherwise 0.)

... OR "Floating" a new item:

  function inv_float_item(Item* item)

For example:

  function inv_float_item(item_sand);

That's it!


VIII. Item Groups
-----------------

Item groups are super easy.  Group_id 0 is special.  If you assign group_id = 0 to a slot, that slot can hold ANY
item.  Let's pretend that you want to make a weapon slot that can ONLY hold weapons.  When you create the sword item,
use the group_id = 4;  Then, when you create the sword slot, set its group_id = 4 too.  Done!


IX. Callbacks
-------------

If you need to know when certain events happen in the inventory system, you'll want to use the callbacks.  I'll explain with an example.  Let's say that you want to know whenever a bag is opened.  First, you need to define a function in your lite-c that will be called when a bag is open.  An open-bag callback function looks like:

a) open_bag_callback

  // put something like this in your lite-c

  function bag_was_opened(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_open_bag_callback() like so:

  set_on_open_bag_callback("bag_was_opened");

Whenever a bag is opened, your function bag_was_opened() will be called.  The bag_id of the opened bag will be passed into your function automatically.  Remember when we first created a bag and I said that the bag_id was useless?  I lied.  Here's where it comes into play.  You can tell which bag was opened by looking at the bag_id that's passed in to your callback function.

b) on_click_callback

This is most complicated callback.  It's triggered whenever someone clicks on a slot.  To use it, add something like this to your lite-c:

  function slot_was_clicked(int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id)
  {
    if (action == INV_ITEM_PLACED)
    {
       // item was placed in bag
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot  
       // removed_item_id is 0 and should be ignored
    }
    if (action == INV_ITEM_REMOVED)
    {
       // item was removed from bag  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is 0 and should be ignored 
       // removed_item_id is the item id that was removed from the slot
    }
    if (action == INV_ITEM_SWAPED)
    {
       // item was put in to a slot that already contained an item, so they were swapped  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot 
       // removed_item_id is the item id that was removed from the slot
    }
  }

And register your callback like:

  set_on_click_callback("slot_was_clicked");


c) on_bag_close_callback

This is just like on_bag_open_callback.  Here's an example:

  function bag_was_closed(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_close_bag_callback() like so:

  set_on_close_bag_callback("bag_was_closed");



X. Other helpful functions
--------------------------

 PANEL* inv_get_bag_panel_ptr(Bag* bag); // given a bag, return its panel pointer
 inv_is_bag_open(Bag* bag); // returns 1 if the bag is open, otherwise 0
 inv_get_open_bag_count(); // returns the number of open bags
 inv_is_floating(); // returns 1 if the player is floating an inventory item
 inv_is_item_in_bag(Bag* bag, Item* item); // returns 1 if the item is in the bag


*/





// ============================ BEGIN CODE =================================


#define new(type) malloc(sizeof(type##))
#define delete(object) free(object)

#define bag_layer 1
#define slot_layer 2
#define floating_item_layer 94

#define INV_ITEM_PLACED 1
#define INV_ITEM_SWAPPED 2
#define INV_ITEM_REMOVED 3

/* 
	struct Item

	The item structure holds a single item's information.  Items are intended to 
	track inventory icons only.  They're not really meant to manage an entire
	game's items.  For example, you would NOT use the item struct to hold values
	such as damage or defense rating for a sword.  The id in the item struct is
	intended to help associate these inventory based items with whatever item
	management is used in the game.  The id is set by the game developer to
	any arbitrary value.  The id is used in callback functions.
	
*/

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
	PANEL* slot_panel;
	
	int id;
	int group_id;
	int rel_x_pos;
	int rel_y_pos;
	int width;
	int height;
	
	STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
	int id;
	int is_open;
	
	int drag_region_top_left_x;
	int drag_region_top_left_y;
	int drag_region_bottom_right_x;
	int drag_region_bottom_right_y;

	int close_region_top_left_x;
	int close_region_top_left_y;
	int close_region_bottom_right_x;
	int close_region_bottom_right_y;
	
	PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;
     
} Bag;


// === Floating Item ===

typedef struct
{
	Item* item;
	PANEL* floating_item_panel;
	
} FloatingItem;


// Ugly linked list for keeping track of panels and associated slots

typedef struct SlotPanelAssoc
{
	PANEL* slot_panel;
	Slot* slot;
	struct SlotPanelAssoc* next;
	struct SlotPanelAssoc* prev;
	
} SlotPanelAssoc;


// Another ugly linked list for keeping track of z-order of open bags

typedef struct BagLayer
{
	Bag* bag;
	struct BagLayer* next;
	struct BagLayer* prev;
	
} BagLayer;


// Global variables

SlotPanelAssoc* slot_panel_assoc;
BagLayer* bag_layer_node;
 
FloatingItem* global_floating_item_ptr;

int inv_floating_flag;
int inv_open_bag_count; // The number of open bags
int inv_item_count; // index used for the inv_items_array
int inv_bag_count;  // index used for the inv_bags_array

Item* inv_items_array[5000];  // Global array to hold item pointers.  Used by cleanup script only.
Bag* inv_bags_array[100]; // Again, store all created bags in this array so we can properly deallocate them later.


// =============== FUNCTIONS =============================================================


// function prototypes

function inv_close_bag(Bag*);
function _inv_do_float(FloatingItem*);
function _inv_drag_bag(Bag*, int drag_offset_x, int drag_offset_y);

function addBagLayer(Bag*);
function removeBagLayer(Bag*);
function reorderBagLayers();
function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel);
function removeSlotPanelAssoc(Slot* slot);

function getSlotPtrForPanelPtr(PANEL* panel_ptr);
function getBagPtrForPanelPtr(PANEL* panel_ptr);


// Callback function prototypes

void on_click_callback_function_ptr(int inv_action, int bag_id, int slot_id, int placed_item_id, int removed_item_id);
void on_float_end_callback_function_ptr();
void on_close_bag_callback_function_ptr(int bag_id);
void on_open_bag_callback_function_ptr(int bag_id);




// --------------- Inventory Function -----------------------------------
 
/* // ORIGINAL FUNCTION 
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  

}
*/

// NEW FUNCTION

function inv_init() 
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  
	
	on_click_callback_function_ptr = NULL;
	on_float_end_callback_function_ptr = NULL;
	on_close_bag_callback_function_ptr = NULL;
	on_open_bag_callback_function_ptr = NULL;
}
 
function bagOnClick(PANEL* panel_ptr)
{
	Bag* bag;
	
	bag = getBagPtrForPanelPtr(panel_ptr);
	
	// Check to see if the player is dragging the panel
	
	if (bag->drag_region_top_left_x != bag->drag_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->drag_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->drag_region_top_left_x + (bag->drag_region_bottom_right_x - bag->drag_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->drag_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->drag_region_top_left_y + (bag->drag_region_bottom_right_y - bag->drag_region_top_left_y))))
		{
			_inv_drag_bag(bag,mouse_pos.x - bag->bag_panel->pos_x, mouse_pos.y - bag->bag_panel->pos_y);
		}
	}
	
	if (bag->close_region_top_left_x != bag->close_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->close_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->close_region_top_left_x + (bag->close_region_bottom_right_x - bag->close_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->close_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->close_region_top_left_y + (bag->close_region_bottom_right_y - bag->close_region_top_left_y))))
		{
			inv_close_bag(bag);
			return(0);
		}
	}

	// Bring bag to the front

	removeBagLayer(bag);		
	addBagLayer(bag);		

	reorderBagLayers();

}

function _inv_drag_bag(Bag* bag, int drag_offset_x, int drag_offset_y)
{
	int i;
		
	while(mouse_left)
	{
		
		vec_set(mouse_pos,mouse_cursor);
					
		// Move bag
		bag->bag_panel->pos_x = mouse_pos.x - drag_offset_x;
		bag->bag_panel->pos_y = mouse_pos.y - drag_offset_y;
		
		// Move all slots
		for (i=0; i < bag->_slot_count; i++)
		{
			bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + bag->bag_panel->pos_x;
			bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + bag->bag_panel->pos_y;
		}		
		
		wait(1);
	}
}

function slotOnClick(PANEL* clicked_panel) // KEY TO SOLVING PROBLEM?????????????????????????????????????????????????????????????????????????????????
{

	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	// player clicked on item in inventory while not floating an item
	
	diag("test1");
	
	if (global_floating_item_ptr->item == NULL)
	{
		diag("test2");

		if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
		{
			
			diag("\ngrab started\n");
			
			// optionally callback with action, bag_id, slot_id, item_id
			if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);


			// Create the floating panel
			
			global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
			
			// Set the item and panel image of the floating item structure.  This effectively "floats"
			// the item that was stored in the inventory slot.
			
			global_floating_item_ptr->item = clicked_slot->item;
			global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
			global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
			
			// Set the item pointer of the clicked on slot to NULL
			
			clicked_slot->item = NULL;
			
			// Restore inventory slot image to be the default background image
			
			clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			

			inv_floating_flag = 1;
			_inv_do_float(global_floating_item_ptr);
			

		}
	}
	else
	{
		diag("test3");

		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
				
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
	
}

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
		
}



function _inv_do_float(FloatingItem* floating_item)
{
	proc_mode = PROC_LATE;
		
	mouse_mode = 4;
	mouse_pointer = 1;
	 
	while(inv_floating_flag == 1)
	{
		floating_item->floating_item_panel.pos_x = mouse_pos.x + 10;
		floating_item->floating_item_panel.pos_y = mouse_pos.y + 10;
		wait(1);		
	}

	// optionally do a callback when floating ends
		
	if (on_float_end_callback_function_ptr) on_float_end_callback_function_ptr();

}

function inv_float_item(Item* item)
{
	
	global_floating_item_ptr->item = item;
	global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
	global_floating_item_ptr->floating_item_panel->bmap = bmap_create(item->floating_icon);
	
	global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
	
	inv_floating_flag = 1; // set global floating flag
	
	_inv_do_float(global_floating_item_ptr);
	
	return global_floating_item_ptr;
}


function inv_create_bag(int bag_id, STRING* image_name)
{
	Bag* bag;
	bag = new(Bag);
	
	bag->image_name = image_name;
	bag->id = bag_id;
	
	// Initialize slot_count to 0
	bag->_slot_count = 0;
	bag->is_open = 0;
	
	// Add bag to global array for cleanup purposes

	inv_bags_array[inv_bag_count] = bag;
	inv_bag_count++;
	
	return bag;
}

function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->drag_region_top_left_x = top_left_x;	
	bag->drag_region_top_left_y = top_left_y;	
	bag->drag_region_bottom_right_x = bottom_right_x;	
	bag->drag_region_bottom_right_y = bottom_right_y;
}

function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->close_region_top_left_x = top_left_x;	
	bag->close_region_top_left_y = top_left_y;	
	bag->close_region_bottom_right_x = bottom_right_x;	
	bag->close_region_bottom_right_y = bottom_right_y;
}

function inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position)
{
	bag->bag_panel = pan_create("",bag_layer_node);
	bag->bag_panel->bmap = bmap_create(bag->image_name);
	bag->bag_panel->event = bagOnClick;

	bag->is_open = 1;
	
	int i;
	
	// Add slots
	
	for (i=0; i < bag->_slot_count; i++)
	{
		
		bag->slots[i]->slot_panel = pan_create("",slot_layer);
		
		if (bag->slots[i]->item == NULL)
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->background_image);
		}
		else
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->item->inventory_icon);
		}
		
		bag->slots[i]->slot_panel->event = slotOnClick;
		bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + panel_x_position;
		bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + panel_y_position;
		
		// Make the new slot panel visible
		bag->slots[i]->slot_panel->flags |= VISIBLE;
		
		// Add this panel and slot to the linked list
		addSlotPanelAssoc(bag->slots[i],bag->slots[i]->slot_panel);
	}
	
	bag->bag_panel->pos_x = panel_x_position;
	bag->bag_panel->pos_y = panel_y_position;
		
	bag->bag_panel->flags |= VISIBLE;
	
	if (on_open_bag_callback_function_ptr) on_open_bag_callback_function_ptr(bag->id);
	
	inv_open_bag_count++;
	
	// Add the pointer to this bag to the front of a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	addBagLayer(bag);
	reorderBagLayers();
	
}

function inv_close_bag(Bag* bag)
{
	if (bag == NULL) 
	{
		diag("\nWARNING: inv_close_bag called with argument NULL\n");
		return 0;
	}

	bag->is_open = 0;
	
	int i;
	
	for (i=0; i < bag->_slot_count; i++)
	{
		// Remove each slot panel
		pan_remove(bag->slots[i]->slot_panel);
		
		// Remove the slot from the associative array
		removeSlotPanelAssoc(bag->slots[i]);
	}

	// remove bag panel
	
	pan_remove(bag->bag_panel);
	
	if (on_close_bag_callback_function_ptr) on_close_bag_callback_function_ptr(bag->id);
		
	inv_open_bag_count--;
	
	// Remove the pointer to this bag from a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	
	removeBagLayer(bag);		
}

//***********************************************************************************************************************************************************************

/*

// ORIGINAL FUNCTION

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}
*/

// NEW FUNCTION

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
	new_slot->slot_panel = NULL;	// <---- NEW LINE
	
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

/*

// ORIGINAL FUNCTION

function inv_insert_item_into_bag(Bag* bag, Item* item)  // COULD THIS SOLVE THE PROBLEM?????????????????????????????????????????????????????????????????????
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
			}
		}
	}
	
	return 0;
}

*/

// NEW FUNCTION

function inv_insert_item_into_bag ( Bag* bag, Item* item )
{
	int i;
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;
					if ( bag->slots[i]->slot_panel )				
						bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,bag->id,bag->slots[i]->id,item->id,NULL);
					return 1;
				}
			}
		}
	}
	
	return 0;
}

function inv_cleanup()
{
	diag("\nStarting inventory cleanup\n");
	
	int i;
	int j;
	
	// Clean up items
	
	Item* item;
	
	for(i=0;i<inv_item_count;i++)
	{
		diag("\n   * cleaning up inventory item");
		item = inv_items_array[i];
		
		if (item != NULL)
		{
			free(item->floating_icon);
			free(item->inventory_icon);
			free(item);
			diag(" - success");
		}
	}
	
	// Clean up bags
	
	Bag* bag;
	
	for (i=0; i<inv_bag_count; i++)
	{
		diag("\n   * cleaning up bag");		
		bag = inv_bags_array[i];
		
		if (bag != NULL)
		{
			// Clean up slots in bag

			for (j=0; j < bag->_slot_count; j++)
			{
				diag("\n     - cleaning up slot");
				free(bag->slots[j]->background_image);
				free(bag->slots[j]);
			}			
			
			free(bag->image_name);
			free(bag);
		}		
	}
	
	free(global_floating_item_ptr);
	
	diag("\nCompleted inventory cleanup\n");
	
}


// ------------- Helpful functions --------------

function inv_get_bag_panel_ptr(Bag* bag)
{
	return bag->bag_panel;	
}

function inv_is_bag_open(Bag* bag)
{
	if (bag == NULL) return 0;
	return bag->is_open;
}

function inv_get_open_bag_count()
{
	return inv_open_bag_count;
}

function inv_is_floating()
{
	return inv_floating_flag;
}

function inv_is_item_in_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i]->item == item)
		{
			return 1;
		}
	}
	
	return 0;
}


// ------------- Create Callback Functions ---------

function set_on_click_callback(STRING* function_name) { on_click_callback_function_ptr = engine_getscript(function_name); } //******************************************************
function set_on_float_end_callback(STRING* function_name) { on_float_end_callback_function_ptr = engine_getscript(function_name); }
function set_on_close_bag_callback(STRING* function_name) { on_close_bag_callback_function_ptr = engine_getscript(function_name); }
function set_on_open_bag_callback(STRING* function_name) { on_open_bag_callback_function_ptr = engine_getscript(function_name); }



// --------------- linked-list functions --------------------------------

// ** list functions for managing bag z order

function addBagLayer(Bag* bag)
{
	if(bag_layer_node == NULL)
	{
		bag_layer_node = new(BagLayer);
		bag_layer_node->bag = bag;

		bag_layer_node->next = NULL;
		bag_layer_node->prev = NULL;
	}
	else
	{
		// Create a new BagLayer struct and put it at the beginning of the list
		BagLayer* new_bag_layer_node = new(BagLayer);
		new_bag_layer_node->bag = bag;
				
		bag_layer_node->prev = new_bag_layer_node;
		new_bag_layer_node->next = bag_layer_node;
		new_bag_layer_node->prev = NULL;
		
		bag_layer_node = new_bag_layer_node;
	}
	
}

function removeBagLayer(Bag* bag)
{
	int first_node = 1;
	
	BagLayer* iterator = bag_layer_node;
	
	while(iterator != NULL)
	{
		if (iterator->bag == bag)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;
			
			if (first_node) bag_layer_node = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function reorderBagLayers()
{
	int new_bag_layer = 90;
	int sanity_check = 0;
	int i;
	
	BagLayer* iterator = bag_layer_node;
	Bag* bag;
		
	while(iterator != NULL)
	{
		// Chage bag layer
		bag = iterator->bag;		
		layer_sort(bag->bag_panel,new_bag_layer);
		
		// Change bag's slot layers
		for (i=0; i < bag->_slot_count; i++)
		{
			layer_sort(bag->slots[i]->slot_panel,new_bag_layer + 1);
		}		
		
		new_bag_layer -= 3;
		iterator = iterator->next;
		
		sanity_check++;
		if (sanity_check > 100) 
		{
			diag("ERROR: reorderBagLayers has run amok!");
			break;
		}
	}
	
}

// ** list functions for storing associations between panels and slots

function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel)
{
	if(slot_panel_assoc == NULL)
	{
		slot_panel_assoc = new(SlotPanelAssoc);
		slot_panel_assoc->slot_panel = slot_panel;
		slot_panel_assoc->slot = slot;

		slot_panel_assoc->next = NULL;
		slot_panel_assoc->prev = NULL;
		
	}
	else
	{
		// Create a new slot_panel_assoc struct and put it at the beginning of the list
		SlotPanelAssoc* new_slot_panel_assoc = new(SlotPanelAssoc);
		new_slot_panel_assoc->slot_panel = slot_panel;
		new_slot_panel_assoc->slot = slot;
				
		slot_panel_assoc->prev = new_slot_panel_assoc;
		new_slot_panel_assoc->next = slot_panel_assoc;
		new_slot_panel_assoc->prev = NULL;
		
		slot_panel_assoc = new_slot_panel_assoc;
	}
}

function removeSlotPanelAssoc(Slot* slot)
{
	int first_node = 1;

	SlotPanelAssoc* iterator = slot_panel_assoc;
	
	while(iterator != NULL)
	{
		if (iterator->slot == slot)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;

			if (first_node) slot_panel_assoc = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function getSlotPtrForPanelPtr(PANEL* panel_ptr)
{
	SlotPanelAssoc* iterator = slot_panel_assoc;

	if (iterator == NULL) 
	{
		diag("\nWARNING: getStructForPanelPtr returned NULL.");
	}
	
	while(iterator != NULL)
	{
		if (iterator.slot_panel == panel_ptr)
		{
			return(iterator.slot);
		}
		iterator = iterator->next;
	}
	
	return NULL;
}

/* 

	getBagPtrForPanelPtr(PANEL* panel_ptr)
 
	Given a panel pointer, return a pointer to the bag having that panel.
	In this case, we're lucky because the bags are all stored in the
	global inv_bags_array.  Why not store the slots in a similar array? --
	Because they're constantly created and destroyed.
	
*/

function getBagPtrForPanelPtr(PANEL* panel_ptr)
{
	int i;
	Bag* bag;
	
	for (i=0;i<inv_bag_count;i++)
	{
		bag = inv_bags_array[i];
		
		if (bag->bag_panel == panel_ptr)
		{
			return bag;
		}	
	}
	
	return NULL;
	
}



Any help would be much appreciated. Thank you.
Posted By: txesmi

Re: Access variable from other program? - 01/08/14 09:32

Yes. It calls the event of the slot: the function responsible for adding a weapon to your players hand.

Salud!
Posted By: txesmi

Re: Dropping items from inventory bag - 01/08/14 10:20

Check 'inv_is_floating' function to know if there is a mouse item.

Code:
if ( inv_is_floating() )
{
...



The module has no function to get and clear the floating icon so I wrote one:

Code:
var inv_get_floating_icon_item_id ()
{
	if ( !inv_floating_flag  )
		return -1;
	inv_floating_flag = 0;
	Item *item = global_floating_item_ptr->item;
	global_floating_item_ptr->item = NULL;		
bmap_remove(global_floating_item_ptr->floating_item_panel->bmap);
pan_remove(global_floating_item_ptr->floating_item_panel);
);
	return item->id;
}



Code:
if ( inv_is_floating() )
{ 
   var item_id = inv_get_floating_item_id ()
   if ( item_id == SWORD_ID )
   {
      ...


Posted By: rayp

Re: Dropping items from inventory bag - 01/08/14 13:35

@Ruben
Merged posts. Please stop open same topic-threads (inventory.c) every third day. Thank you.
Posted By: Ruben

Re: Dropping items from inventory bag - 01/12/14 11:16

@ txesmi
So you placed the inv_get_floating_icon_item_id() function into inventory.c , and called on this function from the main function in OrcStronghold.c ?

So far, I placed the inv_get_floating_icon_item_id() function into inventory.c , as shown here:

Code:
var inv_get_floating_icon_item_id ()
{
	if ( !inv_floating_flag  )
		return -1;
	inv_floating_flag = 0;
	Item *item = global_floating_item_ptr->item;
	global_floating_item_ptr->item = NULL;		
   bmap_remove(global_floating_item_ptr->floating_item_panel->bmap);
   pan_remove(global_floating_item_ptr->floating_item_panel);
   
	return item->id;
}



...and placed this code into the main function of OrcStronghold.c :

Code:
if ( inv_is_floating() )
   { 
      var item_id = inv_get_floating_icon_item_id ();
      if(item_id == MACE_ID)
      {
          ent_create ( "RubensMedievalMace.mdl", vector(-72.355,-549.575,-47.624), mace_action); 
      }
   }



When I click on an item in the inventory bag, and drag that same item outside the inventory bag, and click again, the image of the item is not disappearing and being removed from the inventory bag. No matter how much I click and drag the item image outside the inventory bag, nothing is happening. The item image is still intact, and is not leaving the inventory bag.

Is the argument in the if statement placed in the main function correct in checking whether the player clicked an inventory item outside the inventory bag?
Posted By: txesmi

Re: Dropping items from inventory bag - 01/12/14 13:51

As you said, you have to check if the mouse button is clicked out of the inventory.

Code:
if ( !mouse_panel )
{
	if ( inv_is_floating() )
	{
		if ( mouse_left )
		{
			var item_id = inv_get_floating_icon_item ();
			switch ( item_id )
			{
				case SNIPERGUN:   ent_create ( "snipergun.mdl",  nullvector, NULL );  break;
				case SHOTGUN:     ent_create ( "shotgun.mdl",    nullvector, NULL );  break;
				case MACHINEGUN:  ent_create ( "machinegun.mdl", nullvector, NULL );  break;
			}
		}
	}
}

Posted By: Ruben

Re: Dropping items from inventory bag - 01/14/14 10:42

I tried placing this code into my main function in OrcStronghold.c :

Code:
if(!mouse_panel && mouse_left && inv_is_floating)
{
   var item_id = inv_get_floating_icon_item_id ();
   	   	 	   	
   pan_remove(global_floating_item_ptr->floating_item_panel);
   	   	
   switch(item_id)
   {
      case SWORD:  ent_create ("sword.mdl", nullvector, 
         NULL); break;
      case MACE:   ent_create ("mace.mdl", nullvector, NULL); 
         break;
   }
}



However, still nothing is happening when I click a floating item outside the inventory bag, when I am trying to drop it from my inventory. The floating item (like an image of a sword, in the inventory bag, that you are trying to drop) does not disappear.

It seems that I only need to figure out how to remove a floating image of an equipment item, if I want to drop that equipment item from the bag.
Posted By: Ruben

Re: Dropping items from inventory bag - 01/16/14 07:34

@ txesmi:

Would you place your !mouse_panel code in the main function of OrcStronghold.c , or place it in a separate function in OrcStronghold.c , or in inventory.c ?
Posted By: txesmi

Re: Dropping items from inventory bag - 01/16/14 10:22

There are several ways to check the keyboard and mouse inputs but I would add all the mouse left button functionality to the 'on_mouse_left' event.

Code:
#include <acknex.h>
#include <default.c>
#include "inventory.c"

#define PRAGMA_PATH "%EXE_DIR%\\templates\\sounds"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\images"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\models"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\levels"

#define MAIN_BAG_ID        1
#define ACTIV_WPN_SLOT_ID  0

#define SNIPERGUN          1
#define SHOTGUN            2
#define MACHINEGUN         3

SOUND *sndReload = "reload.wav";
SOUND *sndDrop = "getready.wav";
SOUND *sndShot = "shot2.wav";

Bag *bag = NULL;
Item *gun1 = NULL;
Item *gun2 = NULL;
Item *gun3 = NULL;
ENTITY *active_weapon = NULL;

action active_weapon_action ()
{
	ENTITY *ent = active_weapon;
	if ( ent )
	{
		ent.x = 70;
		ent.y = -20;
		ent.z = -20;
		while ( ent == active_weapon )
			wait(1);
		ent_remove ( ent );
	}
}

function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				active_weapon = NULL;
			}
		}   
   }
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				switch ( placed_item_id )
				{
					case SNIPERGUN:  
						active_weapon = ent_createlayer ( "snipergun.mdl", SHOW, 1 );  
						break;
					case SHOTGUN:    
						active_weapon = ent_createlayer ( "shotgun.mdl", SHOW, 1 );    
						break;
					case MACHINEGUN: 
						active_weapon = ent_createlayer ( "machinegun.mdl", SHOW, 1 ); 
						break;
				}
				active_weapon_action ();  
				snd_play ( sndReload, 100, 0 );
			}
		}   
	}
}

ENTITY *create_scenery_object ( var type, VECTOR *vecPos )
{
	ENTITY *ent = NULL;
	switch ( type )
	{
		case SNIPERGUN:  
			ent = ent_create ( "snipergun.mdl",  vecPos, NULL ); 
			break;
		case SHOTGUN:    
			ent = ent_create ( "shotgun.mdl",    vecPos, NULL ); 
			break;
		case MACHINEGUN: 
			ent = ent_create ( "machinegun.mdl", vecPos, NULL ); 
			break;
	}
	if ( ent )
	{
		ent->skill1 = type;
		snd_play ( sndDrop, 100, 0 );
	}
	return ent;
}

void onMouseLeft ()
{
	if ( mouse_panel )
		return;
	
	if ( inv_is_floating() )
	{
		VECTOR vecTemp;
		vec_set ( vecTemp, mouse_dir3d );
		vec_scale ( vecTemp, 1000 );
		vec_add ( vecTemp, camera.x );
		c_trace ( camera.x, vecTemp, IGNORE_PASSABLE );
		if ( HIT_TARGET )
		{
			vec_set ( vecTemp, hit.x );
			vecTemp.z += 10;
			var item_id = inv_get_floating_icon_item ();
			ENTITY *entObject = create_scenery_object ( item_id, hit.x );
		}
	}
	else if ( mouse_ent )
	{
		ENTITY *ent = NULL;
		switch ( mouse_ent.skill1 )
		{
			case SNIPERGUN:  
				inv_insert_item_into_bag ( bag, gun1 ); 
				ent = mouse_ent; 
				break;
			case SHOTGUN:    inv_insert_item_into_bag ( bag, gun2 ); 
				ent = mouse_ent; 
				break;
			case MACHINEGUN: inv_insert_item_into_bag ( bag, gun3 ); 
				ent = mouse_ent; 
				break;
		}
		if ( ent )
		{
			wait(1); // ent_remove needs a wait before calling it from a 3dgs event
			ent_remove ( ent );
		}
	}
	else
	{
		snd_play ( sndShot, 100, 0 );
	}
}

void newLevel ()
{
	level_load ( "" );
	ENTITY *entTerrain = ent_create( "water.hmp", nullvector, NULL );
	entTerrain.flags2 |= UNTOUCHABLE;
	camera.x = -200;
	camera.z = 400;
	camera.tilt = -60;
	inv_run_slot_callback ( bag, ACTIV_WPN_SLOT_ID );
}

function main()
{
	mouse_mode = 4;
   inv_init();
	
   gun1 = inv_create_item ( SNIPERGUN, 1, "icon2.pcx", "icon2.pcx" );
   gun2 = inv_create_item ( SHOTGUN, 1, "icon3.pcx", "icon3.pcx" );
   gun3 = inv_create_item ( MACHINEGUN, 1, "icon4.pcx", "icon4.pcx" );

   bag = inv_create_bag ( MAIN_BAG_ID,"bluebar.pcx");
   inv_add_slot_to_bag ( bag, ACTIV_WPN_SLOT_ID, 1, "flash2.tga", 0, 0 );
   inv_add_slot_to_bag(bag,1,0,"flash2.tga",0,120);
   inv_add_slot_to_bag(bag,2,0,"flash2.tga",0,180);
   inv_add_slot_to_bag(bag,3,0,"flash2.tga",0,240);
   
   inv_insert_item_into_bag ( bag, gun1 );
   inv_insert_item_into_bag ( bag, gun2 );
   inv_insert_item_into_bag ( bag, gun3 );
   
   set_on_click_callback ( "slot_was_clicked" );
   on_mouse_left = onMouseLeft;
   on_space = newLevel;
   
   newLevel ();
   inv_open_bag ( bag, 0, 0 );
   
   while ( !key_esc )
		wait(1);
   
   sys_exit ( NULL );
}

Posted By: txesmi

Re: Dropping items from inventory bag - 01/16/14 12:36

doble post blush

Anyway you have to hear about the great benefits of using arrays to allocate your data.

If your item pointers are sorted into an array and you fill the inventory item id with its array index you can avoid all those ugly switch-case blocks.

Code:
Item *myItems[3];
#define SNIPERGUN          0 
#define SHOTGUN            1
#define MACHINEGUN         2

//instead of
Item *itemSnipergun = NULL;
Item *itemShotgun = NULL;
Item *itemMachinegun = NULL;



Since the answer of the inventory.c functions is the id of the item, you can build parallel data structs with the data you need to manage the items from the inventory to the scenery and viceversa.

For example, you need the file name of the entities when you drop them from the inventory. You can build a TEXT struct with all your item file names and use the item id to create the entity.

Code:
Item *myItems[3];
TEXT *txtItemModelNames = { strings = 3; }
#define SNIPERGUN          0 
#define SHOTGUN            1
#define MACHINEGUN         2

// When you create each item you fill the filenames,
myItems[SNIPERGUN] = inv_create_item ( SNIPERGUN,  1, "icon2.pcx", "icon2.pcx" );
inv_insert_item_into_bag ( bag, myItems[SNIPERGUN] );
str_cpy ( (txtItemModelNames.pstring)[SNIPERGUN], "snipergun.mdl" );

// So you can create the proper entity with the item id
ENTITY *ent = ent_create ( (txtItemModelNames.pstring)[item_id], vecPos, NULL );

// instead of
if ( item_id == SNIPERGUN )
   ENTITY *ent = ent_create ( "snipergun.mdl", vecPos, NULL );
if ( item_id == SHOTGUN )
   ENTITY *ent = ent_create ( "shotgun.mdl", vecPos, NULL );
if ( item_id == MACHINEGUN )
   ENTITY *ent = ent_create ( "machinegun.mdl", vecPos, NULL );

// or
switch ( item_id )
{
   case SNIPERGUN:
      ENTITY *ent = ent_create ( "snipergun.mdl", vecPos, NULL );
      break;
   case SHOTGUN:
   ...
}



In order to pick an object from the scenery and add it to the inventory it should have the item id stored somewhere. So when you drop an object you save the item id in the newly created entity and when you pick an object you use its saved item id to add it to the inventory.

Code:
// object dropped
ENTITY *ent = ent_create ( (txtItemModelNames.pstring)[item_id], vecPos, NULL );
ent.skill1 = item_id;

// object picked
inv_insert_item_into_bag ( bag, myItems[mouse_ent.skill1] );



Here the example I gived you above using arrays
Code:
#include <acknex.h>
#include <default.c>
#include "inventory.c"

#define PRAGMA_PATH "%EXE_DIR%\\templates\\sounds"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\images"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\models"
#define PRAGMA_PATH "%EXE_DIR%\\templates\\levels"

#define MAIN_BAG_ID        1
#define ACTIV_WPN_SLOT_ID  0

SOUND *sndReload = "reload.wav";
SOUND *sndDrop = "getready.wav";
SOUND *sndShot = "shot2.wav";

ENTITY *active_weapon = NULL;
Bag *bag = NULL;

Item *myItems[3];
TEXT *txtItemModelNames = { strings = 3; }

#define SNIPERGUN          0 
#define SHOTGUN            1
#define MACHINEGUN         2


action active_weapon_action ()
{
	ENTITY *ent = active_weapon;
	if ( ent )
	{
		ent.x = 70;
		ent.y = -20;
		ent.z = -20;
		while ( ent == active_weapon )
			wait(1);
		ent_remove ( ent );
	}
}

function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				active_weapon = NULL;
			}
		}   
   }
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				active_weapon = ent_createlayer ( (txtItemModelNames.pstring)[placed_item_id], SHOW, 1 );
				active_weapon_action ();  
				snd_play ( sndReload, 100, 0 );
			}
		}   
	}
}

ENTITY *create_scenery_object ( var type, VECTOR *vecPos )
{
	ENTITY *ent = ent_create ( (txtItemModelNames.pstring)[type], vecPos, NULL ); 
	ent->skill1 = type;
	snd_play ( sndDrop, 100, 0 );
	return ent;
}

void onMouseLeft ()
{
	if ( mouse_panel )
		return;
	
	if ( inv_is_floating() )
	{
		VECTOR vecTemp;
		vec_set ( vecTemp, mouse_dir3d );
		vec_scale ( vecTemp, 1000 );
		vec_add ( vecTemp, camera.x );
		c_trace ( camera.x, vecTemp, IGNORE_PASSABLE );
		if ( HIT_TARGET )
		{
			vec_set ( vecTemp, hit.x );
			vecTemp.z += 10;
			var item_id = inv_get_floating_icon_item ();
			ENTITY *entObject = create_scenery_object ( item_id, hit.x );
		}
	}
	else if ( mouse_ent )
	{
		ENTITY *ent = mouse_ent;
		inv_insert_item_into_bag ( bag, myItems[mouse_ent.skill1] ); 
		wait(1); // ent_remove needs a wait before calling it from a 3dgs event
		ent_remove ( ent );
	}
	else if ( active_weapon )
	{
		snd_play ( sndShot, 100, 0 );
	}
}

void newLevel ()
{
	level_load ( "" );
	ENTITY *entTerrain = ent_create( "water.hmp", nullvector, NULL );
	entTerrain.flags2 |= UNTOUCHABLE;
	camera.x = -200;
	camera.z = 400;
	camera.tilt = -60;
	inv_run_slot_callback ( bag, ACTIV_WPN_SLOT_ID );
}

function main()
{
	mouse_mode = 4;
   inv_init();
	
   bag = inv_create_bag ( MAIN_BAG_ID,"bluebar.pcx");
   inv_add_slot_to_bag ( bag, ACTIV_WPN_SLOT_ID, 1, "flash2.tga", 0, 0 );
   inv_add_slot_to_bag ( bag, 1,0,"flash2.tga",0,120);
   inv_add_slot_to_bag ( bag, 2,0,"flash2.tga",0,180);
   inv_add_slot_to_bag ( bag, 3,0,"flash2.tga",0,240);
   
   myItems[SNIPERGUN] = inv_create_item ( SNIPERGUN,  1, "icon2.pcx", "icon2.pcx" );
   inv_insert_item_into_bag ( bag, myItems[SNIPERGUN] );
   str_cpy ( (txtItemModelNames.pstring)[SNIPERGUN], "snipergun.mdl" );
   
   myItems[SHOTGUN] = inv_create_item ( SHOTGUN,    1, "icon3.pcx", "icon3.pcx" );
   inv_insert_item_into_bag ( bag, myItems[SHOTGUN] );
   str_cpy ( (txtItemModelNames.pstring)[SHOTGUN], "shotgun.mdl" );

   myItems[MACHINEGUN] = inv_create_item ( MACHINEGUN, 1, "icon4.pcx", "icon4.pcx" );
   inv_insert_item_into_bag ( bag, myItems[MACHINEGUN] );
   str_cpy ( (txtItemModelNames.pstring)[MACHINEGUN], "machinegun.mdl" );

   set_on_click_callback ( "slot_was_clicked" );
   on_mouse_left = onMouseLeft;
   on_space = newLevel;
   
   newLevel ();
   inv_open_bag ( bag, 0, 0 );
   
   while ( !key_esc )
		wait(1);
   
   sys_exit ( NULL );
}



Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 01/28/14 05:05

Thank you txesmi.

I tried incorporating some of your code into my program.

So far, this is what my OrcStronghold.c program looks like:

Code:
...

function change_mouse_mode()
{
   mouse_mode += 1;
   mouse_mode %= 2;

   if (mouse_mode == 1)
   {
      mouse_map = cursor_pcx;
   }
   
}

...


// switch to toggle inventory:
void toggleInventory()
{
	// put some comparisons here:
	// f.e. if we are dead, don't allow to toggle inventory:
	if(player.HEALTH <= 0)
	{ 
		return; 
	}
	// toggle var:
	invOpen += 1;
	invOpen %= 2;
	
	// if we've opened the inventory:
	if(invOpen == 1)
	{
		// show the mouse pointer:

		change_mouse_mode();
		mouse_mode = 1;
		
		// PUT IN CODE FOR INVENTORY GUI
		
	   inv_open_bag ( bag, 375, 75 );  // OPEN INVENTORY BAG CODE
	}
	else
	{

	   mouse_mode = 0;
	   inv_close_bag(bag);
   }
}

action Player()
{
   ...

   on_i = toggleInventory; 
   on_m = change_mouse_mode;
	
   set_on_click_callback("inv_run_slot_callback");

   while (my.x)
   {
      ...
   }

   ...
}

function inv_run_slot_callback ( Bag *bag, var slot_id ) 
{
	if ( !on_click_callback_function_ptr )
		return 0;
	
	int i = 0;
	for ( ; i<bag->_slot_count; i++ )
	{
		Slot *slot = bag->slots[i];
		if ( slot->id != slot_id )
			continue;
		Item *item = slot->item;
		if ( !item )
			return 0;
		on_click_callback_function_ptr ( INV_ITEM_PLACED, bag->id, slot->id, item->id, NULL );
		return 1;
	}
	return 0;
}



With this code, the game goes fine, until I bring up my inventory bag by pressing the "i" key. The inventory bag will come up, and I can even arm my player with a weapon using it. However, when I press the "i" key again to close the inventory bag, my player will move like normal for about a second, but then freeze in place.

Do you know what bug in this code might be causing this? I have been trying to figure it out myself.
Posted By: Ruben

Re: Dropping items from inventory bag - 01/28/14 05:34

Never mind txesmi. I think I screwed up somewhere. Let me get back to you.
Posted By: WretchedSid

Re: Dropping items from inventory bag - 01/28/14 07:17

I'm broke as fuck, but Txsemi, if you give me your paypal address (via PM), I'll send you 10€ for your patience in this thread.
Posted By: txesmi

Re: Dropping items from inventory bag - 01/28/14 09:26

Thanks Sid!
Anything goes to increase the spanish gdp and put us out of slavery grin
Posted By: Ruben

Re: Dropping items from inventory bag - 01/29/14 06:24

Too bad this site does not give me the luxury of deleting posts already made.
Posted By: Ruben

Re: Dropping items from inventory bag - 01/29/14 06:36

I do applaud and thank you txesmi for being willing to help me with understanding and working with this open source inventory.c code. You seem to be one of the rare few that can understand it well.
Posted By: Ruben

Re: Dropping items from inventory bag - 02/02/14 00:41

txesmi: I am looking at your sample code, specifically at this function of yours:

Code:
action active_weapon_action ()
{
	ENTITY *ent = active_weapon;
	if ( ent )
	{
		ent.x = 70;
		ent.y = -20;
		ent.z = -20;
		while ( ent == active_weapon )
			wait(1);
		ent_remove ( ent );
	}
}



I am assuming that this function is meant to position a gun in front of the camera, so that the gun points at wherever the player is facing.

I am trying to change this, in that instead of positioning a gun to point wherever the player faces, I would like to place a hand weapon (like a sword or mace) into the hand of the player. I currently have a function that works in making this happen, but it is not really part of a program that uses arrays.

This is the code that I used (pre-arrays) to place the weapon into the hand of the player:

Code:
action attach_weapon() 
{
	set(my,PASSABLE);
	proc_mode = PROC_LATE;
	
	while (player != NULL) 
	{
		vec_for_vertex(temp.x,player,997); //hand palm base: Vector # 987 on player
		vec_for_vertex(temp2.x,player,968); //hand palm tip: Vector # 982 on player
		vec_set(my.x,temp.x);
		vec_diff(temp.x,temp2.x,temp.x);
		vec_to_angle(my.pan,temp.x); 
		vec_set(my.pan,my.pan);
		wait(1);
	}
}



This code worked for me in attaching a hand weapon to the player's hand, to use as a weapon.

Do you know how I would incorporate the logic of my attach_weapon() function to work in your active_weapon_action() function?

Here is what I tried so far:

Code:
action active_weapon_action ()
{
	ENTITY *ent = active_weapon;
	if ( ent )
	{
		set(my,PASSABLE);
	   proc_mode = PROC_LATE;
	
	   while (player != NULL) 
	   {
	   	vec_for_vertex(temp.x,player,997); //hand palm base: Vector # 987
		   vec_for_vertex(temp2.x,player,968); //hand palm tip: Vector # 982
		   vec_set(my.x,temp.x);
		   vec_diff(temp.x,temp2.x,temp.x);
		   vec_to_angle(my.pan,temp.x); 
		   vec_set(my.pan,my.pan);
		   wait(1);
	   }
		while ( ent == active_weapon )
			wait(1);
		ent_remove ( ent );
	}
}


...but it does not seem to be working. It is not adding a weapon to my player's hand when I place a weapon into the active weapon slot.

Any help would be appreciated. Thanks.
Posted By: txesmi

Re: Dropping items from inventory bag - 02/02/14 23:03

Hi Ruben,
I don't know where to start. I fear that answering your question and giving you the solution is not really a good solution. It will probably become to a similar problem in very few code lines.

Forget about my code by the moment and look at yours. It is absolutely necessary to understand its content before trying to adapt nothing. Socrates would say that the answer was in you all the time (maieutics) so...

Could you explain each code line contained into your 'attach_weapon' function? Let me read it. Be neat!

If not, could you enumerate, explain and reference each pointer into your 'attach_weapon' function?

If not, do you know what a pointer is?

If not, take the time to read the AUM liteC pointers tutorial (at least twice :D)

With manual and pointers in your circle of acquaintances you should be able to answer the second question and probably the first and yours. If not, I can guide you to find the problem by yourself. It deserves the effort. Otherwise I can not easily explain what is wrong.

Does this help?

pd: peripheral reading: AUM liteC structs tutorial
Posted By: Ruben

Re: Dropping items from inventory bag - 02/05/14 06:29

I think that I am not ready to change my whole program to accommodate arrays. It was already working without them, however inefficient it may be. I think my current goal should be to look into learning how to use the callback functions in inventory.c to allow me to drop items from the inventory bag. I believe I may be able to do this with the set_on_float_end_callback() callback function, but I am trying to figure out how.

Any help in that direction would be greatly appreciated. Thanks.
Posted By: txesmi

Re: Dropping items from inventory bag - 02/05/14 10:46

ok, I see.

I feel 'on_float_end_callback_function_ptr' event a bit useless. It is called when you pick an object from the inventory or when you add an item to the mouse pointer using 'inv_float_item' function.

When you pick an object from the inventory, the 'on_click_callback_function_ptr' function is called with INV_ITEM_REMOVED or INV_ITEM_SWAPPED as first parameter. So there are two different event calls for the same internal game action.

When you add an item to the mouse pointer with 'inv_float_item' you are already executing a function of your own so you can perform whatever you want just after the 'inv_float_item' function call. There is no need of an event call at all.

I go back to the previous question. It has nothing to do with the arrays part. You are probably creating the player weapon this way, isn't it?
Code:
active_weapon = ent_create ( (txtItemModelNames.pstring)[SWORD], vecPos, attach_weapon_action );



Here you have to understand that the 'active_weapon' pointer is filled after executing the entity action. So when the entity action is executed the 'active_weapon' pointer points to the previous weapon, not the newly created one! In the case of the first entity action call 'active_weapon' is NULL because there is no previous weapon.

Let us see what happens when the entity action is called at entity creation.

Code:
action active_weapon_action ()
{
	ENTITY *ent = active_weapon;


You are declaring the ENTITY pointer 'ent' and filling it with the content of the global ENTITY pointer 'active_weapon'. So in the first call 'ent' will be equal to NULL (as I explained you) and in the next calls it will be equal to the previous weapon.

As you can imagine this action start is wrong. In my example 'active_weapon_action' is called after asigning the newly created entity (it was a view entity!) address to the 'active_weapon' pointer so in the action start it has already the correct actual weapon pointer asigned to 'active_weapon'.

Code:
if ( ent )
{



In the first call 'ent' is equal to NULL so the conditioning becomes false and the code inside its brackets is not executed: the weapon will never be positioned at players hand.

The slot event (the function that manages the 'active_weapon' pointer) sets 'active_weapon' to NULL when any of INV_ITEM_REMOVED or INV_ITEM_SWAPPED event types are called so the 'ent_create' function will always be called with the 'active_weapon' pointer previously set to NULL and same as at first call will happen: the weapon will never be positioned at players hand.

I apologize for the mess you've gotten to use 'ent_createlayer' instead of 'ent_create'.

Solution:
Click to reveal..

1. Attach your old 'attach_weapon' action to the newly created weapon (with 'ent_create!). At this point, it will simply run but forever: its ending condition is an empty 'player' pointer! So the player will pile all the armed weapons on its hand; repeated inclusive.

2. Set the 'active_weapon' pointer to 'me' at the beginning of the weapon action. This way when you create a new weapon the global 'active_weapon' pointer will point to the newly created weapon from that time and it can be used into the entity action on its first loop.

3. Add a loop that waits for a correctly filled 'player' pointer before using it.

4. Change the running condition of the weapon action. It should break the loop when the active weapon changes to any other weapon instead of the actual 'player != NULL'. This way the weapon action loop will run while the created entity continues been the active weapon.

5. Remove every weapon when it stops being the active weapon. Tip: Inside its action.

6. Try to imagine the impact of this code line (inside 'attach_weapon')
Code:
vec_set(my.pan,my.pan);




Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 02/06/14 05:22

Maybe I am using your new code technique wrong, but when I incorporate it into my program, I am getting weird bugs that I did not have before, and my game is just not working right like it did before.

Going back to my previous code that works, this is the function that works in arming my player with a weapon, when I arm the player using the active weapon slot of the inventory bag:

Code:
function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
			}
		}   
   }
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				switch ( placed_item_id )
				{
					case SWORD:  active_weapon_mdl = "sword.mdl"; active_weapon = ent_create ( active_weapon_mdl, player.x, attach_weapon );  break;
					case MACE:   active_weapon_mdl = "mace.mdl"; active_weapon = ent_create ( active_weapon_mdl, player.x, attach_weapon );  break;
				}
			}
		}   
	}
}


I am now trying to figure out how to create a function that will drop the weapon or item from the inventory bag that the mouse cursor is currently floating, while the inventory bag is open, as the player clicks outside the bag.
Posted By: Ruben

Re: Dropping items from inventory bag - 02/08/14 07:56

Is there a way that I can drop items from my inventory bag without using the arrays method? The code I had before worked just fine without any bugs. If I can find a solution using the code I had before the arrays code, that would be easier for me.
Posted By: txesmi

Re: Dropping items from inventory bag - 02/08/14 08:51

You can find the same code but without arrays in the previous message crazy
Posted By: Ruben

Re: Dropping items from inventory bag - 02/08/14 21:39

Okay, I believe I had part of the functionality I was looking for all along. Its just that my inventory bag GUI was blocking the player, so I could not see what was happening when I drag/clicked an item outside the inventory bag.

It looks like when I drag/click an active weapon outside the inventory bag, the weapon does automatically disappear from the player's hand, since that weapon item icon is no longer in the active weapon slot of the inventory bag. So, I guess I had that functionality all along without realizing it.

My main goal at this point is to make it so that the item icon (from the inventory bag) that I drag/click outside the inventory bag needs to disappear. This should automatically remove it from the player's inventory list.

My goal after that is to make it so that if the item icon disappears after drag/clicking it outside the inventory bag, that same dropped item needs to appear on the ground next to the player.
Posted By: Ruben

Re: Dropping items from inventory bag - 02/09/14 00:46

So, I am trying to remove (delete) the floating inventory icon that I click outside the inventory bag. I created a callback function called item_was_dropped() . Here are both of my callback functions so far:

Code:
function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   {
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
			}
		}   
   }
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				switch ( placed_item_id )
				{
					case SWORD:  active_weapon_mdl = "sword.mdl"; active_weapon = ent_create ( active_weapon_mdl, player.x, attach_weapon );  break;
					case MACE:   active_weapon_mdl = "mace.mdl"; active_weapon = ent_create ( active_weapon_mdl, player.x, attach_weapon );  break;
				}
			}
		}   
	}
}

function item_was_dropped()
{
	Item* floatingItem;

   if ( !mouse_panel )
	{
		if ( inv_is_floating() )
		{
			if ( mouse_left )
			{
				bmap_remove(floatingItem.floating_icon);
			}
		}
	}
}



In my main function, I make some calls to these callback functions:

Code:
set_on_click_callback("slot_was_clicked");
   set_on_float_end_callback("item_was_dropped");



My "slot_was_clicked" function is used for arming the player with a weapon, if a player places a weapon icon into the active weapon slot of the inventory bag. The "slot_was_clicked" callback function works great.

I am trying to make my "item_was_dropped" function to drop items out of my inventory bag when drag/clicking an item icon outside the inventory bag. I am not sure if I am on the right path with this. Am I using the right command ( bmap_remove ) to delete the floating inventory icon when drag/clicking it outside the inventory bag? I know that the code used above for the "item_was_dropped" callback function is not performing what I want it to do (i.e. it is not performing anything).
Posted By: txesmi

Re: Dropping items from inventory bag - 02/10/14 11:32

Hi Ruben,
I divided the 'inv_get_floating_icon_item' function I gived you above into two different functions for better understanding and usage. It was a bit messy.

Code:
function inv_clear_floating_icon ()
{
	if ( inv_floating_flag )
	{
		inv_floating_flag = 0;
		global_floating_item_ptr->item = NULL;		
		bmap_remove(global_floating_item_ptr->floating_item_panel->bmap);
		pan_remove(global_floating_item_ptr->floating_item_panel);
	}
}

var inv_get_floating_icon_item_id ()
{
	if ( inv_floating_flag )
	{
		return global_floating_item_ptr->item->id; 
	}
	else
	{
		error ( "Not existent floating icon on 'inv_get_floating_icon_item_id'.\nValidate the existence of a floating icon before calling 'inv_get_floating_icon_item_id'." );
		return -1;
	}
}



So your 'item_was_dropped' funtion into my example could look as follows:
Code:
#define skill_id   skill20
...
action actObject ()
{
	...
}

function item_was_dropped ()
{
	if ( !mouse_panel ) // Is the mouse pointer out of a panel?
	{
		if ( inv_is_floating() ) // Does a floating icon exists?
		{
			if ( mouse_left ) // Is the mouse left button pressed?
			{
				var item_id = inv_get_floating_icon_item_id (); // Get the floating icon item id.
				inv_clear_floating_icon (); // Clear the floating icon.
				switch ( item_id ) // Create the new scenery object.
				{
					case SNIPERGUN: 
						ENTITY *entObject = ent_create ( "snipergun.mdl", player.x, actObject );
						entObject.skill_id = item_id;
						break;
					case SHOTGUN: 
						ENTITY *entObject = ent_create ( "shotgun.mdl", player.x, actObject );
						entObject.skill_id = item_id;
						break;
					case SHOTGUN: 
						ENTITY *entObject = ent_create ( "machinegun.mdl", player.x, actObject );
						entObject.skill_id = item_id;
						break;
				}
			}
		}
	}
}



Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 02/12/14 09:24

Interesting.

I put your top code into the inventory.c program.

I tried using the logic of your second code in my OrcStronghold.c program. Here is what I have in OrcStronghold.c :

Code:
...

action dropObject ()
{
	// Code to place weapon on ground next to player, when it is dropped.
}

...

function item_was_dropped ()
{
	Bag *bagPanel;
	if ( !mouse_panel ) // Is the mouse pointer out of a panel?
	{
		if ( inv_is_floating() ) // Does a floating icon exists?
		{
			if ( mouse_left ) // Is the mouse left button pressed?
			{
				var item_id = inv_get_floating_icon_item_id (); // Get the floating icon item id.
				inv_clear_floating_icon (); // Clear the floating icon.
				switch ( item_id ) // Create the new scenery object.
				{
					case SWORD: 
						ENTITY *entObject = ent_create ( "sword.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
					case MACE: 
						ENTITY *entObject = ent_create ( "mace.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
				}
			}
		}
	}
}



The code still does not work when I click on an inventory icon saved in the inventory bag, drag it outside the inventory bag, and click that same item icon outside the inventory bag. The inventory icon does not disappear.

I wonder, am I still clicking on some hidden panel when trying to drop an item from my inventory bag?
Posted By: txesmi

Re: Dropping items from inventory bag - 02/12/14 11:10

You should use a sound or a log entry and isolate the not working code line:

Code:
#define PRAGMA_PATH "%EXE_DIR%\\templates\\sounds"
SOUND *sndBeep = "beep.wav";



Play it to the beginning of your function
Code:
function item_was_dropped ()
{
	snd_play ( sndBeep, 100, 0 ); // Is 'item_was_dropped' properly called?
	...



In the case it sounds, move it to the next flux control:
Code:
function item_was_dropped ()
{
	if ( !mouse_panel ) // Is the mouse pointer out of a panel?
	{
		snd_play ( sndBeep, 100, 0 ); // is it?



Anyway it is a mistery for us the way you call your 'item_was_dropped' function and it can come from there.

Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 02/13/14 04:21

Thanks txesmi.

I tried your idea. This is what I created:

Code:
function item_was_dropped ()
{
	Bag *bagPanel;
	
	
	snd_play ( sndDebugger, 100, 0 );
	
	if ( !mouse_panel ) // Is the mouse pointer out of a panel?
	{
		snd_play ( sndDebugger, 100, 0 );
		
		if ( inv_is_floating() ) // Does a floating icon exists?
		{
			snd_play ( sndDebugger, 100, 0 );
			
			if ( mouse_left ) // Is the mouse left button pressed?
			{
				snd_play ( sndDebugger, 100, 0 );
				
				var item_id = inv_get_floating_icon_item_id (); // Get the floating icon item id.
				inv_clear_floating_icon (); // Clear the floating icon.
				switch ( item_id ) // Create the new scenery object.
				{
					case SWORD: 
						ENTITY *entObject = ent_create ( "sword.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
					case MACE: 
						ENTITY *entObject = ent_create ( "mace.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
				}
			}
		}
	}
}



When I move an inventory icon from one slot of the inventory bag into a different slot, I hear the DEBUGGER sound, which is an explosion. If I click/drag an inventory icon from being saved in the inventory bag, to a location outside the bag, and left-click, I am not hearing the debugger exploding sound, and nothing happens. So, for some reason, "!mousepanel" does not seem to be registering the clicking outside the inventory bag.
Posted By: txesmi

Re: Dropping items from inventory bag - 02/13/14 08:56

The first 'snd_play' is before '!mouse_panel' so the problem is earlier. Check where, when and how you call your 'item_was_dropped' function. It needs to be called every frame.

Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 04/13/14 04:31

I have still not solved this problem, for the program is still not allowing me to drop items from the inventory bag.

I am trying out a new technique. Instead of checking to see if I clicked outside a mouse_panel , I am checking to see if my mouse cursor is outside a certain range of x/y screen pixels (outside the inventory GUI itself) instead. This is the code that I am trying to use to drop an item from my player's inventory bag by click/floating an item outside the inventory bag, left-clicking, and hoping that the item's floating image will disappear from the inventory bag, and show up on the ground next to the player:

Code:
...

#include "inventory.c"

...

var mouse_x;
var mouse_y;

...

function change_mouse_mode()
{	
   mouse_mode += 1;
   mouse_mode %= 2;
   
   if (mouse_mode == 1)
   {
      mouse_map = cursor_pcx;
   }
   
   mouse_pos.x = mouse_cursor.x;
   mouse_pos.y = mouse_cursor.y;
   
   
   while(1) // DEBUGGER THAT SHOWS CURRENT PIXEL LOCATIONS FOR MOUSE CURSOR IN THE pDisplay PANEL BELOW
   {
      mouse_x = mouse_pos.x;
      mouse_y = mouse_pos.y;

      wait(1);
   }
}

...

// DEBUGGER PANEL USED TO SHOW THE CURRENT POSITION OF THE MOUSE CURSOR AT SCREEN PIXEL X AND SCREEN PIXEL Y.

PANEL* pDisplay =
{
        digits (620, 40, 5, *, 1, mouse_x); // DEBUGGER: MOUSE CURSOR X LOCATION
	digits (620, 70, 5, *, 1, mouse_y); // DEBUGGER: MOUSE CURSOR Y LOCATION

	flags = SHOW;
}

...

function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
   	Bag *bagPanel;
	
   	if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
				
				if(placed_item_id == NULL)
				{
					weapon_code = fist_code;
				}
			}
		}   
   	}
   	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
   	{
   		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				switch ( placed_item_id )
				{
					case SWORD:   activate_sword();  break;
					case MACE:    activate_mace();  break; 
					default:      weapon_code = fist_code; break;
				}
			}
		}   
   	}
   	if(inv_is_floating)
   	{
      		snd_play ( sndExploDebug, 100, 0 );
		
      		if ((mouse_y <= 73) || (mouse_y >= 313) || (mouse_x >= 263))
      		{
			if ( mouse_left )
			{
				snd_play ( sndDebugger, 100, 0 );
				
				var item_id = inv_get_floating_icon_item_id (); // Get the floating icon item id.
				inv_clear_floating_icon (); // Clear the floating icon.

				switch ( item_id ) // Create the new scenery object.
				{
					case SWORD: 
						ENTITY *entObject = ent_create ( "sword.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
					case MACE: 
						ENTITY *entObject = ent_create ( "mace.mdl", player.x, dropObject );
						entObject.skill_id = item_id;
						break;
				}
			}
		}
   	}
}

...

function main()
{
	...

	set_on_click_callback("slot_was_clicked");

	while(1)
   	{
   		if ( active_weapon != NULL )
   		active_weapon->pan += 5*time_step;
   		
   		mouse_pos.x = mouse_cursor.x;
      		mouse_pos.y = mouse_cursor.y;
      
      		// if we've enabled the mouse:
      		if(mouse_mode > 0)
      		{
      			// move it's position with a cursor:
      			vec_set(mouse_pos.x, mouse_cursor.x);
      	
      		}
   		
   		wait(1);
	}
	
	sys_exit ( NULL );
}



The pDisplay panel in the above code actually shows the current location of the mouse cursor with the X and Y screen pixels of its location, so it appears that mouse_x and mouse_y are storing the correct location coordinates of the mouse cursor.

In the code above, on this line of code in the slot_was_clicked() function:

if ((mouse_y <= 73) || (mouse_y >= 313) || (mouse_x >= 263))

...the inventory bag GUI starts on Screen Pixel Y = 73, and goes to Screen Pixel Y = 313. The inventory bag GUI also starts from the very left side of the screen, and ends on Screen Pixel = 263. So in other words, if my mouse cursor is floating an inventory item, the mouse cursor is within the above Screen Pixel range, and the left mouse button was clicked simultaneously, I am trying to initiate this code:
Code:
snd_play ( sndExploDebug, 100, 0 ); // DEBUG EXPLOSION SOUND
				
var item_id = inv_get_floating_icon_item_id (); // Get the floating icon item id.
inv_clear_floating_icon (); // Clear the floating icon.

switch ( item_id ) // Create the new scenery object.
{
	case SWORD: 
		ENTITY *entObject = ent_create ( "sword.mdl", player.x, dropObject );
		entObject.skill_id = item_id;
		break;
	case MACE: 
		ENTITY *entObject = ent_create ( "mace.mdl", player.x, dropObject );
		entObject.skill_id = item_id;
		break;
}



I do not hear the debug explosion sound when I click/float an inventory item image, and left-click within the Screen Pixel range given above, which lets me know that this part of the function is not activating.

I set the variable item_id equal to the file title of the floating icon image by using the inv_get_floating_icon_item_id() function from inventory.c , and try to recreate the same item on the ground next to the player, like the player dropped the item on the ground. The inv_clear_floating_icon() function from inventory.c is supposed to delete the current floating icon. However, none of these actions are happening.

Here is the inventory.c code that I am using to create an inventory for the player in my game:

Code:
// 
// Inventory.c - programmed by Bret Truchan.  You are welcome to use this inventory
// system in the creation of commercial or free games.  You may not use it for any
// other purpose.
// 

/*


DOCUMENTATION

Table of Contents

   I. Introduction
  II. Essentials: inv_init() and inv_cleanup()
 III. Creating items for your inventory
  IV. Making your first bag
   V. Opening and Closing bags
  VI. Setting bag close and drag regions
 VII. Adding items to bags

VIII. Item Groups
  IX. Callbacks
  X. Other helpful functions


I. Introduction
---------------

Hello fellow programmer!  I hope that you can find the following inventory
system useful.  My main goal when making this inventory system was to decouple
the inventory system from the rest of the game code.  I also wanted to make it
as easy as possible to create and manage your inventory system.

This inventory has the following features:

1. Easy to use
2. Supports multiple bags
3. Handles the layering of bags for you
4. Supports callbacks for inventory events
5. Supports item "groups". (For example, gerbils can only be put in gerbil
slots.)

I modeled the inventory system after World of Warcraft.  One limitation to this
system is that slots in bags really need to be the same size.  I know how to 
fix this so, for example, your sword would show up huge in the sword slot but
small in a backpack slot, but I'll have to save that for a later release.



II. Essentials: inv_init() and inv_cleanup()
--------------------------------------------

Let's dive right in.  Creating your inventory is done in your lite-c code. 
You should not need to modify inventory.c.  Before anything else, include
inventory.c in your code, like so:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c" // <---- ADDED THIS

 void main()
 {
   inv_init(); // <---- ADDED THIS
   wait(1); // <---- ADDED THIS

   // etc..

Add the inv_init(); function call to your main loop as shown above.  Because
inventory.c uses some low level C structures, you need to call inv_cleanup()
just before your game closes.


III. Creating items for your inventory
--------------------------------------

Let's skip ahead and create some images that will be needed for your
inventory.  If you have the demo for this inventory code, you can use my demo
images.

  pack.pcx - The is the background image of your inventory pack.
  slot_bg.pcx - The background image of an empty slot.
  item1.pcx - An icon of an item, such as a sword.  This should be the same
size as slot_bg.pcx.

Ok, back to items....

Items are strange.  You might think of an item like a "sword" or "gun". 
However, this inventory system is NOT trying to control how you manage items
for your game.  Although you might have a "sword" item in your inventory, the
structure that's passed around in the inventory code should NOT have
attributes such as "damage" or "weight".

Let's move ahead with an example of adding your first item - A pile of sand.
Maybe this pile of sand will go into your nephew's Christmas Stocking
because he ate all your friggin' cookies?!

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");


See that inv_create_item(...) statement?  inv_create_item() creates an abstract
item in your inventory system. Let's break it down:

 item_pointer = inv_create_item(item_id,group_id,floating_icon,inventory_icon);

Arguments:

 item_id - You make this up.  It can be anything that you want.  It doesn't affect the inventory engine.
 
 group_id - Later on, slots will also have a group id.  Items can only be put into slots with the right group id.

 floating_icon - The image used for the item while it's being dragged around the inventory system.

 inventory_icon - The image for displaying the item when the item is in a slot.

To reiterate, we introduced a new item into our inventory system.  We gave it an item id of 1, which really doesn't mean anything.  We gave it a group_id = 0, which means that the item can be placed into any slot having group_id=0.  We choose the same image "item1.pcx" for the icon used to "float" the item around in the inventory as well as the icon that represents the item in a slot.  That's good enough for now.  We'll keep moving forward..


IV. Making your first bag
-------------------------

There are a few terms that I loosly introduced above.  Your inventory may have multiple "bags".  Bags have multiple "slots", and slots may contain items.  Let's make our first bag.  Luckily, it's pretty easy:

 #include <acknex.h>
 #include <default.c>
 #include "inventory.c"

 Item* item_sand;
 Bag* bag; // <---- added this line

 void main()
 {
   inv_init();
   wait(1);

   item_sand = inv_create_item(1,0,"item1.pcx","item1.pcx");
   bag = inv_create_bag(1,"pack.pcx");  // <---- added this line


Easy!  When you do this, the bag does not appear on the screen.  We'll handle that later.  For now, let's look closely at the
inv_create_bag() function:

   bag = inv_create_bag(bag_id,bag_image);

Arguments

 bag_id - You make this up.  It's not used within the inventory system, but it can be useful when handling callbacks.  We'll  
 discuss callbacks later on.

 bag_image - This should be an image of your open inventory bag.


Creating a bag is only half the battle.  Generally, you use the inv_add_slot_to_bag() function to add
a slot to your bag.  Here's the generic version:

  function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)

Arguments:

  bag - The bag that you created above.
  slot_id - Any value that you like.  It's only used for callbacks, which I'll cover later.
  group_id - Only items having this value may be added to the slot.
  default_image - An image showing an empty slot.
  rel_x_pos - x position relative to the top left of the bag's image
  rel_y_pos - y position relative to the top left of the bag's image

Here's a real world example of creating 4 slots to your bag:

  inv_add_slot_to_bag(bag,1,0,"slot_bg.pcx",9,38);
  inv_add_slot_to_bag(bag,2,0,"slot_bg.pcx",44,38);
  inv_add_slot_to_bag(bag,3,0,"slot_bg.pcx",78,38);
  inv_add_slot_to_bag(bag,4,0,"slot_bg.pcx",112,38);


V. Opening and Closing bags
---------------------------

Opening bags is easy:

  inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position);

That's it!  Here's use a real world example:

  inv_open_bag(bag, 100,100);

Closing your bag is even easier:

  inv_close_bag(bag);

We haven't added items to bags yet, but you'll see that it's very easy. When you open and close bags, the bags remember what items they contained.  You don't need to re-add the items.


VI. Setting bag close and drag regions
--------------------------------------

This inventory system allows you to drag bags around the screen and close them.  It's optional.  All you need to do is tell the inventory system where the drag region and close region are on the bag image.  Here's an example:

  inv_set_bag_drag_region(bag,5,3,128,18);
  inv_set_bag_close_region(bag,129,0,148,19);

The arguments are:

 function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
 function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)

Quick note:  For multiple bags, the inventory code automatically handles which bag should be "on top" if they overlap.


VII. Adding items to bags
-------------------------

Believe it or not, you're almost done.  Adding items to the inventory system can be done in two ways.  First, you can add an item directly to a bag.  Alternatively, you can create an item and immediately have it "float" (which means that the icon is visible and is being dragged by the mouse).

Adding an item directly to a bag:

  function inv_insert_item_into_bag(Bag* bag, Item* item)

For example:

  inv_insert_item_into_bag(bag,item_sand);

  (This function will return 1 if there was room in the bag for the item, otherwise 0.)

... OR "Floating" a new item:

  function inv_float_item(Item* item)

For example:

  function inv_float_item(item_sand);

That's it!


VIII. Item Groups
-----------------

Item groups are super easy.  Group_id 0 is special.  If you assign group_id = 0 to a slot, that slot can hold ANY
item.  Let's pretend that you want to make a weapon slot that can ONLY hold weapons.  When you create the sword item,
use the group_id = 4;  Then, when you create the sword slot, set its group_id = 4 too.  Done!


IX. Callbacks
-------------

If you need to know when certain events happen in the inventory system, you'll want to use the callbacks.  I'll explain with an example.  Let's say that you want to know whenever a bag is opened.  First, you need to define a function in your lite-c that will be called when a bag is open.  An open-bag callback function looks like:

a) open_bag_callback

  // put something like this in your lite-c

  function bag_was_opened(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_open_bag_callback() like so:

  set_on_open_bag_callback("bag_was_opened");

Whenever a bag is opened, your function bag_was_opened() will be called.  The bag_id of the opened bag will be passed into your function automatically.  Remember when we first created a bag and I said that the bag_id was useless?  I lied.  Here's where it comes into play.  You can tell which bag was opened by looking at the bag_id that's passed in to your callback function.

b) on_click_callback

This is most complicated callback.  It's triggered whenever someone clicks on a slot.  To use it, add something like this to your lite-c:

  function slot_was_clicked(int action, int bag_id, int slot_id, int placed_item_id, int removed_item_id)
  {
    if (action == INV_ITEM_PLACED)
    {
       // item was placed in bag
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot  
       // removed_item_id is 0 and should be ignored
    }
    if (action == INV_ITEM_REMOVED)
    {
       // item was removed from bag  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is 0 and should be ignored 
       // removed_item_id is the item id that was removed from the slot
    }
    if (action == INV_ITEM_SWAPED)
    {
       // item was put in to a slot that already contained an item, so they were swapped  
       // bag_id is the id of the bag where the item was placed
       // slot_id is the id of the slot where the item was placed  
       // placed_item_id is the item id that was placed into the slot 
       // removed_item_id is the item id that was removed from the slot
    }
  }

And register your callback like:

  set_on_click_callback("slot_was_clicked");


c) on_bag_close_callback

This is just like on_bag_open_callback.  Here's an example:

  function bag_was_closed(int bag_id)
  {
    // do something
  }

Then, register this function with the inventory system by calling set_on_close_bag_callback() like so:

  set_on_close_bag_callback("bag_was_closed");



X. Other helpful functions
--------------------------

 PANEL* inv_get_bag_panel_ptr(Bag* bag); // given a bag, return its panel pointer
 inv_is_bag_open(Bag* bag); // returns 1 if the bag is open, otherwise 0
 inv_get_open_bag_count(); // returns the number of open bags
 inv_is_floating(); // returns 1 if the player is floating an inventory item
 inv_is_item_in_bag(Bag* bag, Item* item); // returns 1 if the item is in the bag


*/





// ============================ BEGIN CODE =================================


#define new(type) malloc(sizeof(type##))
#define delete(object) free(object)

#define bag_layer 1
#define slot_layer 2
#define floating_item_layer 94

#define INV_ITEM_PLACED 1
#define INV_ITEM_SWAPPED 2
#define INV_ITEM_REMOVED 3

/* 
	struct Item

	The item structure holds a single item's information.  Items are intended to 
	track inventory icons only.  They're not really meant to manage an entire
	game's items.  For example, you would NOT use the item struct to hold values
	such as damage or defense rating for a sword.  The id in the item struct is
	intended to help associate these inventory based items with whatever item
	management is used in the game.  The id is set by the game developer to
	any arbitrary value.  The id is used in callback functions.
	
*/

typedef struct
{
   int id;
   int group_id;
   STRING* floating_icon;
   STRING* inventory_icon;
} Item;


// === Slot ===

typedef struct
{
	PANEL* slot_panel;
	
	int id;
	int group_id;
	int rel_x_pos;
	int rel_y_pos;
	int width;
	int height;
	
	STRING* background_image;
	
   Item *item;
   
   int bag_id;
   
} Slot;

// === Bag ===

typedef struct
{
	int id;
	int is_open;
	
	int drag_region_top_left_x;
	int drag_region_top_left_y;
	int drag_region_bottom_right_x;
	int drag_region_bottom_right_y;

	int close_region_top_left_x;
	int close_region_top_left_y;
	int close_region_bottom_right_x;
	int close_region_bottom_right_y;
	
	PANEL* bag_panel;
   Slot* slots[16];
   int _slot_count;
   STRING* image_name;
     
} Bag;


// === Floating Item ===

typedef struct
{
	Item* item;
	PANEL* floating_item_panel;
	
} FloatingItem;


// Ugly linked list for keeping track of panels and associated slots

typedef struct SlotPanelAssoc
{
	PANEL* slot_panel;
	Slot* slot;
	struct SlotPanelAssoc* next;
	struct SlotPanelAssoc* prev;
	
} SlotPanelAssoc;


// Another ugly linked list for keeping track of z-order of open bags

typedef struct BagLayer
{
	Bag* bag;
	struct BagLayer* next;
	struct BagLayer* prev;
	
} BagLayer;


// Global variables

SlotPanelAssoc* slot_panel_assoc;
BagLayer* bag_layer_node;
 
FloatingItem* global_floating_item_ptr;

int inv_floating_flag;
int inv_open_bag_count; // The number of open bags
int inv_item_count; // index used for the inv_items_array
int inv_bag_count;  // index used for the inv_bags_array

Item* inv_items_array[5000];  // Global array to hold item pointers.  Used by cleanup script only.
Bag* inv_bags_array[100]; // Again, store all created bags in this array so we can properly deallocate them later.


// =============== FUNCTIONS =============================================================


// function prototypes

function inv_close_bag(Bag*);
function _inv_do_float(FloatingItem*);
function _inv_drag_bag(Bag*, int drag_offset_x, int drag_offset_y);

function addBagLayer(Bag*);
function removeBagLayer(Bag*);
function reorderBagLayers();
function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel);
function removeSlotPanelAssoc(Slot* slot);

function getSlotPtrForPanelPtr(PANEL* panel_ptr);
function getBagPtrForPanelPtr(PANEL* panel_ptr);


// Callback function prototypes

void on_click_callback_function_ptr(int inv_action, int bag_id, int slot_id, int placed_item_id, int removed_item_id);
void on_float_end_callback_function_ptr();
void on_close_bag_callback_function_ptr(int bag_id);
void on_open_bag_callback_function_ptr(int bag_id);




// --------------- Inventory Function -----------------------------------
 
/* // ORIGINAL FUNCTION 
function inv_init()
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  

}
*/

// NEW FUNCTION

function inv_init() 
{
	// Create a instance of the floating item struct and set the global_floating_item_ptr to it
	
	FloatingItem* floating_item = new(FloatingItem);
	floating_item->item = NULL;	
	inv_floating_flag = 0; // set global floating flag
	global_floating_item_ptr = floating_item;  
	
	on_click_callback_function_ptr = NULL;
	on_float_end_callback_function_ptr = NULL;
	on_close_bag_callback_function_ptr = NULL;
	on_open_bag_callback_function_ptr = NULL;
}
 
function bagOnClick(PANEL* panel_ptr)
{
	Bag* bag;
	
	bag = getBagPtrForPanelPtr(panel_ptr);
	
	// Check to see if the player is dragging the panel
	
	if (bag->drag_region_top_left_x != bag->drag_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->drag_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->drag_region_top_left_x + (bag->drag_region_bottom_right_x - bag->drag_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->drag_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->drag_region_top_left_y + (bag->drag_region_bottom_right_y - bag->drag_region_top_left_y))))
		{
			_inv_drag_bag(bag,mouse_pos.x - bag->bag_panel->pos_x, mouse_pos.y - bag->bag_panel->pos_y);
		}
	}
	
	if (bag->close_region_top_left_x != bag->close_region_bottom_right_x)
	{
		if ((mouse_pos.x > (bag->bag_panel->pos_x + bag->close_region_top_left_x))
		&& (mouse_pos.x < (bag->bag_panel->pos_x + bag->close_region_top_left_x + (bag->close_region_bottom_right_x - bag->close_region_top_left_x)))
		&& (mouse_pos.y > (bag->bag_panel->pos_y + bag->close_region_top_left_y))
		&& (mouse_pos.y < (bag->bag_panel->pos_y + bag->close_region_top_left_y + (bag->close_region_bottom_right_y - bag->close_region_top_left_y))))
		{
			inv_close_bag(bag);
			return(0);
		}
	}

	// Bring bag to the front

	removeBagLayer(bag);		
	addBagLayer(bag);		

	reorderBagLayers();

}

function _inv_drag_bag(Bag* bag, int drag_offset_x, int drag_offset_y)
{
	int i;
		
	while(mouse_left)
	{
		
		vec_set(mouse_pos,mouse_cursor);
					
		// Move bag
		bag->bag_panel->pos_x = mouse_pos.x - drag_offset_x;
		bag->bag_panel->pos_y = mouse_pos.y - drag_offset_y;
		
		// Move all slots
		for (i=0; i < bag->_slot_count; i++)
		{
			bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + bag->bag_panel->pos_x;
			bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + bag->bag_panel->pos_y;
		}		
		
		wait(1);
	}
}

function slotOnClick(PANEL* clicked_panel) // KEY TO SOLVING PROBLEM?????????????????????????????????????????????????????????????????????????????????
{

	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	// player clicked on item in inventory while not floating an item
	
	diag("test1");
	
	if (global_floating_item_ptr->item == NULL)
	{
		diag("test2");

		if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
		{
			
			diag("\ngrab started\n");
			
			// optionally callback with action, bag_id, slot_id, item_id
			if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);


			// Create the floating panel
			
			global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
			
			// Set the item and panel image of the floating item structure.  This effectively "floats"
			// the item that was stored in the inventory slot.
			
			global_floating_item_ptr->item = clicked_slot->item;
			global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
			global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
			
			// Set the item pointer of the clicked on slot to NULL
			
			clicked_slot->item = NULL;
			
			// Restore inventory slot image to be the default background image
			
			clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			

			inv_floating_flag = 1;
			_inv_do_float(global_floating_item_ptr);
			

		}
	}
	else
	{
		diag("test3");

		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
				
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
	
}

function inv_clear_floating_icon ()
{
	if ( inv_floating_flag )
	{
		inv_floating_flag = 0;
		global_floating_item_ptr->item = NULL;		
		bmap_remove(global_floating_item_ptr->floating_item_panel->bmap);
		pan_remove(global_floating_item_ptr->floating_item_panel);
	}
}

var inv_get_floating_icon_item_id ()
{
	if ( inv_floating_flag )
	{
		return global_floating_item_ptr->item->id; 
	}
	else
	{
		error ( "Not existent floating icon on 'inv_get_floating_icon_item_id'.\nValidate the existence of a floating icon before calling 'inv_get_floating_icon_item_id'." );
		return -1;
	}
}

// END OF NEW CODE

function inv_create_item(item_id, group_id, STRING* floating_icon, STRING* inventory_icon)
{
	// Create item and assign images
	
	Item* item = new(Item);
	item->floating_icon = floating_icon;		
	item->inventory_icon = inventory_icon;
	item->id = item_id;
	item->group_id = group_id;
	
	// Add item to global array for cleanup purposes

	inv_items_array[inv_item_count] = item;
	inv_item_count++;
	
	return item;
		
}



function _inv_do_float(FloatingItem* floating_item)
{
	proc_mode = PROC_LATE;
		
	mouse_mode = 4;
	mouse_pointer = 1;
	 
	while(inv_floating_flag == 1)
	{
		floating_item->floating_item_panel.pos_x = mouse_pos.x + 10;
		floating_item->floating_item_panel.pos_y = mouse_pos.y + 10;
		wait(1);		
	}

	// optionally do a callback when floating ends
		
	if (on_float_end_callback_function_ptr) on_float_end_callback_function_ptr();

}

function inv_float_item(Item* item)
{
	
	global_floating_item_ptr->item = item;
	global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
	global_floating_item_ptr->floating_item_panel->bmap = bmap_create(item->floating_icon);
	
	global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
	
	inv_floating_flag = 1; // set global floating flag
	
	_inv_do_float(global_floating_item_ptr);
	
	return global_floating_item_ptr;
}


function inv_create_bag(int bag_id, STRING* image_name)
{
	Bag* bag;
	bag = new(Bag);
	
	bag->image_name = image_name;
	bag->id = bag_id;
	
	// Initialize slot_count to 0
	bag->_slot_count = 0;
	bag->is_open = 0;
	
	// Add bag to global array for cleanup purposes

	inv_bags_array[inv_bag_count] = bag;
	inv_bag_count++;
	
	return bag;
}

function inv_set_bag_drag_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->drag_region_top_left_x = top_left_x;	
	bag->drag_region_top_left_y = top_left_y;	
	bag->drag_region_bottom_right_x = bottom_right_x;	
	bag->drag_region_bottom_right_y = bottom_right_y;
}

function inv_set_bag_close_region(Bag* bag, int top_left_x, int top_left_y, int bottom_right_x, int bottom_right_y)
{
	bag->close_region_top_left_x = top_left_x;	
	bag->close_region_top_left_y = top_left_y;	
	bag->close_region_bottom_right_x = bottom_right_x;	
	bag->close_region_bottom_right_y = bottom_right_y;
}

function inv_open_bag(Bag* bag, int panel_x_position, int panel_y_position)
{
	bag->bag_panel = pan_create("",bag_layer_node);
	bag->bag_panel->bmap = bmap_create(bag->image_name);
	bag->bag_panel->event = bagOnClick;

	bag->is_open = 1;
	
	int i;
	
	// Add slots
	
	for (i=0; i < bag->_slot_count; i++)
	{
		
		bag->slots[i]->slot_panel = pan_create("",slot_layer);
		
		if (bag->slots[i]->item == NULL)
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->background_image);
		}
		else
		{
			bag->slots[i]->slot_panel->bmap = bmap_create(bag->slots[i]->item->inventory_icon);
		}
		
		bag->slots[i]->slot_panel->event = slotOnClick;
		bag->slots[i]->slot_panel->pos_x = bag->slots[i]->rel_x_pos + panel_x_position;
		bag->slots[i]->slot_panel->pos_y = bag->slots[i]->rel_y_pos + panel_y_position;
		
		// Make the new slot panel visible
		bag->slots[i]->slot_panel->flags |= VISIBLE;
		
		// Add this panel and slot to the linked list
		addSlotPanelAssoc(bag->slots[i],bag->slots[i]->slot_panel);
	}
	
	bag->bag_panel->pos_x = panel_x_position;
	bag->bag_panel->pos_y = panel_y_position;
		
	bag->bag_panel->flags |= VISIBLE;
	
	if (on_open_bag_callback_function_ptr) on_open_bag_callback_function_ptr(bag->id);
	
	inv_open_bag_count++;
	
	// Add the pointer to this bag to the front of a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	addBagLayer(bag);
	reorderBagLayers();
	
}

function inv_close_bag(Bag* bag)
{
	if (bag == NULL) 
	{
		diag("\nWARNING: inv_close_bag called with argument NULL\n");
		return 0;
	}

	bag->is_open = 0;
	
	int i;
	
	for (i=0; i < bag->_slot_count; i++)
	{
		// Remove each slot panel
		pan_remove(bag->slots[i]->slot_panel);
		
		// Remove the slot from the associative array
		removeSlotPanelAssoc(bag->slots[i]);
	}

	// remove bag panel
	
	pan_remove(bag->bag_panel);
	
	if (on_close_bag_callback_function_ptr) on_close_bag_callback_function_ptr(bag->id);
		
	inv_open_bag_count--;
	
	// Remove the pointer to this bag from a linked list of bag pointers.  This
	// linked list is maintained to allow reordering of bags based on layer.
	
	removeBagLayer(bag);		
}

//***********************************************************************************************************************************************************************

/*

// ORIGINAL FUNCTION

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
		
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}
*/

// NEW FUNCTION

function inv_add_slot_to_bag(Bag* bag, int slot_id, int group_id, STRING* default_image, int rel_x_pos, int rel_y_pos)
{
	Slot* new_slot;
	new_slot = new(Slot);

	// Set the position for the new slot
	
	new_slot->rel_x_pos = rel_x_pos;
	new_slot->rel_y_pos = rel_y_pos;	
	new_slot->background_image = default_image;
	new_slot->item = NULL;
	new_slot->id = slot_id;
	new_slot->group_id = group_id;
	new_slot->bag_id = bag->id;	
	new_slot->slot_panel = NULL;	// <---- NEW LINE
	
	bag->slots[bag->_slot_count] = new_slot;
	
	bag->_slot_count += 1;
	
}

/*

// ORIGINAL FUNCTION

function inv_insert_item_into_bag(Bag* bag, Item* item)  // COULD THIS SOLVE THE PROBLEM?????????????????????????????????????????????????????????????????????
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;				
					bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon);
					return 1;
				}
			}
		}
	}
	
	return 0;
}

*/

// NEW FUNCTION

function inv_insert_item_into_bag ( Bag* bag, Item* item )
{
	int i;
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i] != NULL)
		{
			if (bag->slots[i]->item == NULL)
			{
				if ((bag->slots[i]->group_id == item->group_id) || (bag->slots[i]->group_id == 0))
				{
					bag->slots[i]->item = item;
					if ( bag->slots[i]->slot_panel )				
						bag->slots[i]->slot_panel->bmap = bmap_create(item->inventory_icon					);
					if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,bag->id,bag->slots[i]->id,item->id,NULL);
					return 1;
				}
			}
		}
	}
	
	return 0;
}

function inv_cleanup()
{
	diag("\nStarting inventory cleanup\n");
	
	int i;
	int j;
	
	// Clean up items
	
	Item* item;
	
	for(i=0;i<inv_item_count;i++)
	{
		diag("\n   * cleaning up inventory item");
		item = inv_items_array[i];
		
		if (item != NULL)
		{
			free(item->floating_icon);
			free(item->inventory_icon);
			free(item);
			diag(" - success");
		}
	}
	
	// Clean up bags
	
	Bag* bag;
	
	for (i=0; i<inv_bag_count; i++)
	{
		diag("\n   * cleaning up bag");		
		bag = inv_bags_array[i];
		
		if (bag != NULL)
		{
			// Clean up slots in bag

			for (j=0; j < bag->_slot_count; j++)
			{
				diag("\n     - cleaning up slot");
				free(bag->slots[j]->background_image);
				free(bag->slots[j]);
			}			
			
			free(bag->image_name);
			free(bag);
		}		
	}
	
	free(global_floating_item_ptr);
	
	diag("\nCompleted inventory cleanup\n");
	
}

// NEW FUNCTION*********************************************************************************************************************

var inv_get_floating_icon_item_id ()
{
	if ( !inv_floating_flag  )
		return -1;
	inv_floating_flag = 0;
	Item *item = global_floating_item_ptr->item;
	//item = global_floating_item_ptr->item;
	global_floating_item_ptr->item = NULL;		
   bmap_remove(global_floating_item_ptr->floating_item_panel->bmap);
   pan_remove(global_floating_item_ptr->floating_item_panel);
   //);
	return item->id;
}

// ------------- Helpful functions --------------

function inv_get_bag_panel_ptr(Bag* bag)
{
	return bag->bag_panel;	
}

function inv_is_bag_open(Bag* bag)
{
	if (bag == NULL) return 0;
	return bag->is_open;
}

function inv_get_open_bag_count()
{
	return inv_open_bag_count;
}

function inv_is_floating()
{
	return inv_floating_flag;
}

function inv_is_item_in_bag(Bag* bag, Item* item)
{
	int i;
	
	for(i=0;i < bag->_slot_count; i++)
	{
		if (bag->slots[i]->item == item)
		{
			return 1;
		}
	}
	
	return 0;
}


// ------------- Create Callback Functions ---------

function set_on_click_callback(STRING* function_name) { on_click_callback_function_ptr = engine_getscript(function_name); } //******************************************************
function set_on_float_end_callback(STRING* function_name) { on_float_end_callback_function_ptr = engine_getscript(function_name); }
function set_on_close_bag_callback(STRING* function_name) { on_close_bag_callback_function_ptr = engine_getscript(function_name); }
function set_on_open_bag_callback(STRING* function_name) { on_open_bag_callback_function_ptr = engine_getscript(function_name); }



// --------------- linked-list functions --------------------------------

// ** list functions for managing bag z order

function addBagLayer(Bag* bag)
{
	if(bag_layer_node == NULL)
	{
		bag_layer_node = new(BagLayer);
		bag_layer_node->bag = bag;

		bag_layer_node->next = NULL;
		bag_layer_node->prev = NULL;
	}
	else
	{
		// Create a new BagLayer struct and put it at the beginning of the list
		BagLayer* new_bag_layer_node = new(BagLayer);
		new_bag_layer_node->bag = bag;
				
		bag_layer_node->prev = new_bag_layer_node;
		new_bag_layer_node->next = bag_layer_node;
		new_bag_layer_node->prev = NULL;
		
		bag_layer_node = new_bag_layer_node;
	}
	
}

function removeBagLayer(Bag* bag)
{
	int first_node = 1;
	
	BagLayer* iterator = bag_layer_node;
	
	while(iterator != NULL)
	{
		if (iterator->bag == bag)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;
			
			if (first_node) bag_layer_node = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function reorderBagLayers()
{
	int new_bag_layer = 90;
	int sanity_check = 0;
	int i;
	
	BagLayer* iterator = bag_layer_node;
	Bag* bag;
		
	while(iterator != NULL)
	{
		// Chage bag layer
		bag = iterator->bag;		
		layer_sort(bag->bag_panel,new_bag_layer);
		
		// Change bag's slot layers
		for (i=0; i < bag->_slot_count; i++)
		{
			layer_sort(bag->slots[i]->slot_panel,new_bag_layer + 1);
		}		
		
		new_bag_layer -= 3;
		iterator = iterator->next;
		
		sanity_check++;
		if (sanity_check > 100) 
		{
			diag("ERROR: reorderBagLayers has run amok!");
			break;
		}
	}
	
}

// ** list functions for storing associations between panels and slots

function addSlotPanelAssoc(Slot* slot, PANEL* slot_panel)
{
	if(slot_panel_assoc == NULL)
	{
		slot_panel_assoc = new(SlotPanelAssoc);
		slot_panel_assoc->slot_panel = slot_panel;
		slot_panel_assoc->slot = slot;

		slot_panel_assoc->next = NULL;
		slot_panel_assoc->prev = NULL;
		
	}
	else
	{
		// Create a new slot_panel_assoc struct and put it at the beginning of the list
		SlotPanelAssoc* new_slot_panel_assoc = new(SlotPanelAssoc);
		new_slot_panel_assoc->slot_panel = slot_panel;
		new_slot_panel_assoc->slot = slot;
				
		slot_panel_assoc->prev = new_slot_panel_assoc;
		new_slot_panel_assoc->next = slot_panel_assoc;
		new_slot_panel_assoc->prev = NULL;
		
		slot_panel_assoc = new_slot_panel_assoc;
	}
}

function removeSlotPanelAssoc(Slot* slot)
{
	int first_node = 1;

	SlotPanelAssoc* iterator = slot_panel_assoc;
	
	while(iterator != NULL)
	{
		if (iterator->slot == slot)
		{
			// Tie together next and previous nodes
			if (iterator->prev != NULL) iterator->prev->next = iterator->next;			
			if (iterator->next != NULL) iterator->next->prev = iterator->prev;

			if (first_node) slot_panel_assoc = iterator->next;
			
			// Free up removed slotPanelAssoc struct
			delete(iterator);
			
			return 1;
		}
		iterator = iterator->next;
		first_node = 0;
	}
}

function getSlotPtrForPanelPtr(PANEL* panel_ptr)
{
	SlotPanelAssoc* iterator = slot_panel_assoc;

	if (iterator == NULL) 
	{
		diag("\nWARNING: getStructForPanelPtr returned NULL.");
	}
	
	while(iterator != NULL)
	{
		if (iterator.slot_panel == panel_ptr)
		{
			return(iterator.slot);
		}
		iterator = iterator->next;
	}
	
	return NULL;
}

/* 

	getBagPtrForPanelPtr(PANEL* panel_ptr)
 
	Given a panel pointer, return a pointer to the bag having that panel.
	In this case, we're lucky because the bags are all stored in the
	global inv_bags_array.  Why not store the slots in a similar array? --
	Because they're constantly created and destroyed.
	
*/

function getBagPtrForPanelPtr(PANEL* panel_ptr)
{
	int i;
	Bag* bag;
	
	for (i=0;i<inv_bag_count;i++)
	{
		bag = inv_bags_array[i];
		
		if (bag->bag_panel == panel_ptr)
		{
			return bag;
		}	
	}
	
	return NULL;
	
}



Does anyone know why the slot_was_clicked() function is not erasing an inventory image icon from the inventory bag and creating that same item on the ground next to the player when I click/float an inventory item at Screen Pixel Y less than or equal to 73 and greater than or equal to 313, and Screen Pixel X greater than 263; and then left click the mouse?

Any help would be appreciated. Thank you.

Posted By: txesmi

Re: Dropping items from inventory bag - 04/14/14 18:57

Hi Ruben,
there are several troubles with your code.

inv_is_floating is a function. You must call it this way:
Code:
if ( inv_is_floating() )
{...



Anyway looking into inventory.c I saw that the floating icon is created after the event call so it will never be true.

You set slot_was_clicked as the function called when a slot is clicked so you can be totally sure that the mouse is over the clicked slot when the event is called. It is not possible to find the mouse out of the inventory panel when you click over a slot.

Same happens with the mouse buttons. You can be totally sure that the mouse left button is pressed when the slot click event is called (unless enable_mouse is set to 2).

Hope it helps wink
Posted By: txesmi

Re: Dropping items from inventory bag - 04/16/14 08:16

Hi Ruben,
I wanted to give you a new possibility with a little change to inventory.c. I added a new occurrence to the slot click event in order to detect the mouse right button.

You need to add a new macro for the new occurrence
Code:
#define INV_ITEM_RIGHT_CLICK 4 // 354th code line



The modified slotOnClick function: the function added as event to every slot.
Code:
function slotOnClick(PANEL* clicked_panel) 
{
	Slot* clicked_slot = getSlotPtrForPanelPtr(clicked_panel);

	if (clicked_slot == NULL) { diag("\n*** Error: panel not found\n"); }
	
	if (global_floating_item_ptr->item == NULL) 	// player clicked on item in inventory while not floating an item
	{
// 16/04/2014 Addition -----------------------------------------------------
		if ( event_type == EVENT_CLICK ) // mouse left button event
		{
// -------------------------------------------------------------------------
			if (clicked_slot->item != NULL) // Player is grabbing an item out of the inventory
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) 
					on_click_callback_function_ptr(INV_ITEM_REMOVED,clicked_slot->bag_id,clicked_slot->id,0,clicked_slot->item->id);
	
	
				// Create the floating panel
				
				global_floating_item_ptr->floating_item_panel = pan_create("",floating_item_layer);
				
				// Set the item and panel image of the floating item structure.  This effectively "floats"
				// the item that was stored in the inventory slot.
				
				global_floating_item_ptr->item = clicked_slot->item;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot->item->floating_icon);
				global_floating_item_ptr->floating_item_panel->flags |= VISIBLE;
				
				// Set the item pointer of the clicked on slot to NULL
				
				clicked_slot->item = NULL;
				
				// Restore inventory slot image to be the default background image
				
				clicked_slot->slot_panel->bmap = bmap_create(clicked_slot->background_image);			
	
				inv_floating_flag = 1;
				_inv_do_float(global_floating_item_ptr);
				
			}
// 16/04/2014 Addition -----------------------------------------------------
		}
		else if ( event_type == EVENT_RIGHTCLICK ) // mouse right button event
		{
			if (clicked_slot->item != NULL)
			{
				if (on_click_callback_function_ptr) 
					on_click_callback_function_ptr(INV_ITEM_RIGHT_CLICK,clicked_slot->bag_id,clicked_slot->id,clicked_slot->item->id,0);
			}
		}
// -------------------------------------------------------------------------
	}
	else
	{
		if ((clicked_slot->group_id == 0) || (clicked_slot->group_id == global_floating_item_ptr->item->group_id)) // Test to make sure that item can be placed in the slot
		{		
			if (clicked_slot->item == NULL) // player is putting an item into an empty inventory slot
			{
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_PLACED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,0);
				
				// Place item in slot
				clicked_slot->item = global_floating_item_ptr->item;	
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				global_floating_item_ptr->item = NULL;		
	
				// End float
				pan_remove(global_floating_item_ptr->floating_item_panel);
				inv_floating_flag = 0;	
			}		
			else // player is swapping the floating item for the one in the inventory
			{
	
				// optionally callback with action, bag_id, slot_id, item_id
				if (on_click_callback_function_ptr) on_click_callback_function_ptr(INV_ITEM_SWAPPED,clicked_slot->bag_id,clicked_slot->id,global_floating_item_ptr->item->id,clicked_slot->item->id);
				
				
				// Backup the information of the clicked on slot
				Item* clicked_slot_item_pointer = clicked_slot->item;
				STRING* clicked_slot_inventory_icon = str_create(clicked_slot->item->inventory_icon);
				
				// Set the slot to the floating item
				clicked_slot->item = global_floating_item_ptr->item;
				clicked_panel->bmap = bmap_create(global_floating_item_ptr->item->inventory_icon);
				
				// Set the floating item to the slot
				global_floating_item_ptr->item = clicked_slot_item_pointer;
				global_floating_item_ptr->floating_item_panel->bmap = bmap_create(clicked_slot_inventory_icon);
				
			}
		}
	}
}



Since every slot is a panel, they are not buttons, you must set enable_mouse to 2 in order to get the event call when you click with the right mouse button over a slot.

Code:
mouse_mode = 2; // or 4 or whatever you use
enable_mouse = 2;



At this point you should be able to detect the mouse right click over a slot inside your slot_was_clicked function.

Code:
function slot_was_clicked ( int occurrence, int bag_id, int slot_id, int placed_item_id, int removed_item_id ) 
{
	Bag *bagPanel;
	
	if ( ( occurrence == INV_ITEM_REMOVED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				ent_remove ( active_weapon );
				
				if(placed_item_id == NULL)
				{
					weapon_code = fist_code;
				}
			}
		}   
	}
	if ( ( occurrence == INV_ITEM_PLACED ) || ( occurrence == INV_ITEM_SWAPPED ) )
	{
		if (bag_id == MAIN_BAG_ID)
		{
			if (slot_id == ACTIV_WPN_SLOT_ID)
			{
				switch ( placed_item_id )
				{
					case SWORD:   activate_sword();  break;
					case MACE:    activate_mace();  break; 
					default:      weapon_code = fist_code; break;
				}
			}
		}   
	}
	if ( occurrence == INV_ITEM_RIGHT_CLICK )
	{
		snd_play ( sndExploDebug, 100, 0 );
	}
}



This code let you hear the sndExploDebug sound when you click over a filled slot and when you have not an item grabbed.

Imagine you want to drop an item at the player position when you click over a filled slot with the mouse right button. You would need to create a new entity in the scenery and clear the clicked slot. You know how to create a new entity but there is no function to clear a slot. I wrote it for you. Add it to inventory.c and use it into your slot_was_clicked function.

Code:
function inv_clear_slot ( int bag_id, int slot_id )
{
	Bag* bag;
	
	int ii;
	for ( ii=0; ii<inv_bag_count; ii++ )
	{
		bag = inv_bags_array[ii];
		if ( bag->id != bag_id )
			continue;
		
		int i = 0;
		for ( ; i<bag->_slot_count; i++ )
		{
			Slot *slot = bag->slots[i];
			if ( slot->id != slot_id )
				continue;
			
			if ( slot->item == NULL )
				continue;
			
			if (on_click_callback_function_ptr)
				on_click_callback_function_ptr(INV_ITEM_REMOVED,bag_id,slot_id,slot->item->id,slot->item->id);
			
			slot->item = NULL;
			if ( slot->slot_panel != NULL )
				slot->slot_panel->bmap = bmap_create(slot->background_image);
		}
	}
}



This function gets slower the more bags exists but the item index management does not let me build it other way.

Hope it helps
Salud!
Posted By: Ruben

Re: Dropping items from inventory bag - 04/18/14 00:43

txesmi: It worked!!! You are amazing!! I am now able to drop items from the player's inventory bag.

Now I just need to figure out how to make the same dropped item appear on the ground next to the player.

I am totally willing to include you in the credits for this game when it is finished, if you would like. This is a HUGE completed milestone, friend. I have been working quite a long time on this issue. This really made my day. :-D
Posted By: txesmi

Re: Dropping items from inventory bag - 04/19/14 16:04

I'm glad to help grin

Salud!

pd: The clicked slot item id is stored in placed_item_id
Posted By: Ruben

Re: Dropping items from inventory bag - 04/22/14 09:03

Well, I managed to solve all the other bugs with this thread's issue of dropping an inventory item, so, I consider this thread completed.

Thank you all for your help. I greatly appreciate it. This thread truly helped me accomplish a huge milestone in my game. :-)
Posted By: Ruben

Re: Dropping items from inventory bag - 05/02/14 00:12

txesmi: By the way, I sent you a private message.
© 2024 lite-C Forums