adonthell-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Adonthell-devel] Finally, inventories!


From: Kai Sterker
Subject: [Adonthell-devel] Finally, inventories!
Date: Sun, 9 Feb 2003 17:43:26 +0100

As often is the case, I'm writing this mail 'cause it helps me to think
things through properly :). OTOH, if you have concerns with some of the
stuff that will follow, or better ideas, please let me know!



So lets start with the basic design: 2 classes are involved with the
inventory.

A "slot" is the inventory's basic unit. Basically, inventories are just
a list of slots. But as a slot is more than a container for a single
item, it needs to be a full featured class. So what does a slot contain?

Either nothing, a single item, a stack of identical items, or multiple
stacks of roughly identical items. Examples would be a suit of chain
mail, 100 coins or 5 torches in different state of usage.

Since a slot will not contain 100 coin items, but rather one coin item
and the count 100, items should never delete themselves. Instead they
should tell their slot to remove one unit. Therefore, items need to know
the slot they are kept in.

Some care has to be taken that items cannot be easily 'cloned' or
otherwise multiplied.

The "slot" class has at least the following attributes and methods:

- item_base* Item [private]

  The item(s) kept in this slot. It may be a single, immutable item
  in which case it is a mere pointer to the global instance of that
  item. Or it is an instance (or linked list of instances) of a 
  mutable item.

  Only (roughly) equal items may be kept in the same slot. To compare 
  items for equality, their name is used.


- u_int16 Count [private]

  The number of items in the slot. If it contains immutable items,
  then the number is a mere refcount. If it contains mutable items,
  it tells the number of instances that are in the stack.


- string Id [private]

  This can be used in cases where slots shouldn't be interchangeable. 
  That way we can use an inventory to store the items a character
  wears by naming the slots accordingly. Setting this value is optional.
  But its very useful for retrieving slots (and thus the items they may
  contain) from an inventory without having a pointer to the slot.


- inventory * Inventory [private]

  The inventory the slot belongs to. This is required so that the
  slot can inform its inventory of changes that the inventory is
  not aware of. (For example if an item is used up and tells the slot
  to delete itself). The inventory in turn can notify others of the
  change. (The GUI for example).


- unsigned int count () [public]
 
  Returns the number of items in a slot. Can also be used to check
  whether a given slot is empty.

  This method is mainly of interest for a GUI that wants to display
  the number of items in a slot.


- item_base * get_item () [public]

  Returns a pointer to the (first) item in the slot. Again this is
  mainly useful for inventories to access things like the item's icon or
  description.


- bool add_item (item_base * item, int & count) [public]

  Adds an item to the slot. The slot needs to be either empty, or has to
  contain items of roughly the same kind. The items have to be stackable
  of course. If they are stackable, as many items as fit are added to
  the slot. If not all fit, the count parameter will contain the number
  of remaining items. The method will return true if all items fitted,
  false otherwise.

  Some sanity checking can be implemented here as well. If the item in
  question comes from another inventory, it's 'slot' member won't be
  NULL. Therefore, we can automatically remove as many items from the
  old slot as are added to the new one. That means, when moving an item
  from one inventory to another, it needs not be explicitly removed.
  That also means, that if a stack of item does not fit entirely into
  the new inventory, no further action has to be taken, as the part of
  the stack that cannot be transferred will remain in the old inventory.

  Of course, in cases where this is not the desired behaviour (for
  example if one has paid for these items in a shop), the remaining
  items should be placed somewhere where the player can get them (e.g on
  the ground) instead of remaining in the shopkeepers inventory.


- bool remove_item (item_base * item, const int & count = 1) [public]

  Remove the given item from the slot. Removes up to 'count' items.
  Returns false if 'count' greater than items in the slot. If 'count' 
  is -1, then all items will be removed, no matter how many there are.

  That's the method an item should call if it is used up and wants to
  delete itself.

  The item instance needs to be passed to the slot, so we can remove
  the right mutable item in case there is more than one. In case of
  immutable item it wouldn't be needed.


Okay, those are the most basic methods of a slot. More might be needed
later on, but for a first implementation those should suffice.

On to the actual inventory:

- vector<slot*> Slots [private]
  
  The slots an inventory contains. Inventories can have different
  numbers of slots, and they can even grow if required.


- vector of 'listeners' [private]
  
  Not exactly sure how that will be implemented, but I am pretty certain
  that we might want to attach callbacks that are invoked when certain
  'inventory events' occur. Such events could be adding or removing a
  certain item, or some sort of item transition.

  They can be used to update an inventory gui as required, but also for
  gameplay stuff.

  There'd be some methods for registering/unregistering those listeners.
  
  Have to check whether the generic event system is suitable for this
  purpose.


- bool Autogrow [private]

  Whether the inventory may grow on inserting items. Might be useful for
  a keyring, for example, or 'inventories' of maps or shops.


- void add_slot (const string & id) [public]

  Add a slot with the given id. Mainly useful for setting up special
  inventories from python. Otherwise, a special constructor should
  create an inventory with a given number of (anonymous) slots.


- slot * get_slot (const string & id) [public]

  Retrieve the named slot from the inventory. For example 
  get_slot ("Left Ring") or something similar. Apart from items the
  character wears this could be also used to access other 'special'
  slots, like a quiver or a slot associated with a certain action
  button.


- bool add_item (item_base *item, u_int16 & count) [public]

  Similar to slot::add_item. Will search for a slot that contains
  matching items and add them to the stack, if stackable. Otherwise
  will look for an empty slot to add the item to.

  I think we do not need an explicit remove_item method. If items are
  always moved between slots/inventories, removal will happen
  automatically. The same is true when items are simply used up.
  
  Should the need arise, such method could be added however.


- query methods [public]

  We'd need a couple of methods to query an inventory for certain
  items, or properties (like total weight or size). Items could be
  queried by instance, by name or by category.

  Query methods returning items should return one item at a time
  or NULL if no item of that type remains. This means a bit more code to
  write, if for example we want to remove all items of a kind, but OTOH
  it allows equal treatment of mutable and immutable items.


- action methods [public]

  As I said in the mail about item actions, to allow simple combination
  of stacks of items, item actions should be executed via the inventory
  (if desired). The methods should be written such that items may come
  from different inventories (i.e work on slot level). When
  manipulating/using items via the inventory GUI, those methods would be
  called. On other occassions the item actions may be called directly.


Okay, that should be it for now. I am quite happy with everything, so I
will go about coding the stuff to see where problems remain that I
haven't covered. If you have suggestions or ideas, please fire away!

Kai




reply via email to

[Prev in Thread] Current Thread [Next in Thread]