[SOLVED] Need help with making a shop in which you can buy and sell items.

Started by Egmundo Huevoz, Mon 11/12/2017 00:44:28

Previous topic - Next topic

Egmundo Huevoz

Hello! As my title says, I'm trying to make a shop for my game. I've been trying by using a list box inside a GUI. My problem is that when I use the "removeitem" function, the numbers of the rest of the items change, rendering the rest of my code, useless. Also, I'm trying to figure out how to be able to sell and item. I.e. have the desired item disappear from my inventory and show up on the merchant's list box. Is there any module for this already done, or can somebody help me? Thanks in advance...

Khris

#1
Does it have to be a listbox? You could use a GUI with two inventory windows instead, and assign the first one to the player character, the second to the actual merchant character or a dummy character.
If you do that, you can move the items back and forth simply by using Character.Add/LoseInventory().

All you have to do is figure out which item was clicked; for the player you can use custom inv click handling (enable it in General Settings and use on_mouse_click + eMouseLeftInv), for the merchant you'll probably have to use some basic math involving GUI / inv window coordinates and its ItemWidth / ItemHeight.

Edit: one can of course simply use InventoryItem.GetAtScreenXY() for the last part... :P

Egmundo Huevoz

Quote from: Khris on Mon 11/12/2017 02:23:06
Does it have to be a listbox? You could use a GUI with two inventory windows instead, and assign the first one to the player character, the second to the actual merchant character or a dummy character.
If you do that, you can move the items back and forth simply by using Character.Add/LoseInventory().

All you have to do is figure out which item was clicked; for the player you can use custom inv click handling (enable it in General Settings and use on_mouse_click + eMouseLeftInv), for the merchant you'll probably have to use some basic math involving GUI / inv window coordinates and its ItemWidth / ItemHeight.
You're right, it doesn't necessarily have to be a list box, I'm gonna modify the post's title. The thing with your solution is that I wouldn't know where to start. I know, probably being such a noob, it isn't recommended for me to try and do something so complex. But I was hoping somebody already made something like this in one of the numerous AGS games, and could give me the script.

Slasher

I have made a couple of shops. Unfortunately the computer the scripts were on is now defunct.

The whole process depends how you want to have it implemented.

There are various ways to do it.

I did mine by choosing items from a product brochure and having the option to purchase each one...when an item is purchased the item would go into the inventory and money deducted from your total.

Labels to keep check of money got/spent...

There are other options you can add to this.

As I said, it depends how you want it implemented.

PS don't expect anyone to give you a ready-made script...

Khris

#4
Quote from: Egmundo Huevoz on Mon 11/12/2017 12:39:30But I was hoping somebody already made something like this in one of the numerous AGS games, and could give me the script.

I actually might whip up a basic demo game, but I'd have to know how you want this to work regarding money. Are the items going to have a fixed price?

Edit: here you go: https://drive.google.com/open?id=1hy0DMIFftH4R0nEIyKrCq40A_AvULLnV

Khris

Quote from: Slasher on Mon 11/12/2017 14:01:58
I have made a couple of shops. Unfortunately the computer the scripts were on is now defunct.
Btw slasher, you can always pull out the hard drives and connect them to another computer using a USB/SATA cable (Amazon)


Egmundo Huevoz

Quote from: Khris on Mon 11/12/2017 15:56:39
Quote from: Egmundo Huevoz on Mon 11/12/2017 12:39:30But I was hoping somebody already made something like this in one of the numerous AGS games, and could give me the script.

I actually might whip up a basic demo game, but I'd have to know how you want this to work regarding money. Are the items going to have a fixed price?

Edit: here you go: https://drive.google.com/open?id=1hy0DMIFftH4R0nEIyKrCq40A_AvULLnV

For the love of god, this is EXACTLY what I wanted. Hell, it's even better, I didn't even expect to see the items graphics, nor a description... Really, this is great. Maybe for someone as knowledgeable as you, it's not a big deal, but for me, this is gold. I can't thank you enough. Thanks for taking the time to help me.

Khris

You're very welcome ;-D

I've just noticed that I forgot a tiny detail; one should probably insert a ClaimEvent(); at line 47 of the main shop script, to prevent the GlobalScript's on_mouse_click from also handling the inventory click.

Btw, one could display a x2 etc. next to an item instead; let me know if you want that and need help with implementing it.

Egmundo Huevoz

I've been checking your file since I posted my reply. You seem to have read my mind, because that's one of my questions, among others:

1) Very important: how to make items unsellable? Wouldn't want the player selling a key or something.
2) If I were to change the option to make inventory items stack, how would I display the number of such items I have left? Again with the example of 200 potions, you can imagine it would clutter the inventories.
3) Can I add other tags to the items, other than name and value? For instance if I wanted to have tags with the item's type, such as "weapon", "consumable", and so on...
It would read: Large sword - Weapon - $10.
4) Not a question about your shop, but how can I add multiple inventory items with just one line? For instance if I want a merchant to have 200 potions, I wouldn't want to clutter the script with 200 lines. Surely there's a better way. I know it's with "inventoryquantity", but I can't get it to work and the manual's example show's a different thing.

Thanks again, in advance, for all your valuable help.

P.s: I added that line you said :)

Khris

Regarding 4), you can do cMerchant.InventoryQuantity[iPotion.ID] += 200;
It's an array of integers, and you can change it like any other int array. The index is the ID of the inv item, which you can get like shown above. You might have to follow that with UpdateInventory(); if the change doesn't become visible on-screen.

2) takes a bit more work; the basic idea is to have a DynamicSprite for each item (a copy of the item sprite) and DrawString() the amount on it dynamically. I'll update my example game when I get around to it later in the day.

1) and 3) are much easier to achieve, one way is to use more custom properties, like I did to store the dollar value of each item (the name is built-in). Unlike earlier AGS versions, custom properties can now be changed in-game. The alternative used to be to create a custom struct and create an array of data items, each one associated with an InvItem.
Whatever method you choose, I'd suggest to number the types, then assign a type number to each item. If done cleverly, you could have something like an edible weapon (i.e. items can be members of more than one type group).
Same for making them unsellable quest items and the like, or adding weight.

Code: ags
  iPretzelClub.SetProperty["type", typeWeapon | typeEdible];
  iPretzelClub.SetProperty["sellable", 0];


The above uses int typeWeapon = 1, typeEdible = 2; // 4, 8, 16, etc. and a type check can be done like

Code: ags
boolean Is(this InventoryItem*, int type) {
  return this.GetProperty("type") & type > 0;  // I guess? haven't tested this
}

  // some interaction
  if (currentWeapon.Is(typeEdible)) ...

Khris

I updated the files with a solution to show the amount instead.
Link is still the same: https://drive.google.com/open?id=1hy0DMIFftH4R0nEIyKrCq40A_AvULLnV

I did use a button and GUI for this, since it turned out one can't simply change InventoryItem.Graphic, given that player and merchant are usually going to have different amounts of each item.

I also found out that a non-clickable Button covering an InvWindow makes InventoryItem.GetAtScreenXY() return null although other GetAtScreen() methods do work if the thing on top is not clickable, afaik.

Egmundo Huevoz

Quote from: Khris on Fri 15/12/2017 10:26:56
I updated the files with a solution to show the amount instead.
Link is still the same: https://drive.google.com/open?id=1hy0DMIFftH4R0nEIyKrCq40A_AvULLnV

I did use a button and GUI for this, since it turned out one can't simply change InventoryItem.Graphic, given that player and merchant are usually going to have different amounts of each item.

I also found out that a non-clickable Button covering an InvWindow makes InventoryItem.GetAtScreenXY() return null although other GetAtScreen() methods do work if the thing on top is not clickable, afaik.
This works great, thank you very much again! The only thing left for me to ask to you is if you could explain to me how would I make it so essential items don't show on the shop interface, or show but be unsellable. Maybe it's with that piece of code you pasted at the end of your previous post, boolean something or other, IDK (laugh). If it is, were should I put it? I'm sorry for my extreme noobness. :~(

Khris

The shop is heavily based on the inventories of the two characters; the simplest way of not showing certain items is to remove them before opening the shop window, then to give them back when the player closes the shop.
One way to do this is to use a dummy character to store them:
Code: ags
void Store(this InventoryItem*) {
  cStorage.InventoryQuantity[this.ID] = player.InventoryQuantity[this.ID];
  player.InventoryQuantity[this.ID]; = 0;
}

  // before opening the shop:
  iSword.Store();  // this will work even if the player doesn't possess iSword yet
  iShield.Store();

Same in reverse after the shop is closed.

The other alternative is to add a custom property to each inventory item (type: Number, initial value: 0), then set them to 1 for unsellable items.
In the click handler, compare ii.GetProperty("unsellable") against 0 before calling Sell(ii);.

Egmundo Huevoz

I made it! Of course I don't have to explain this to you, but for the noobs who'll see the post in years to come. First I made a new property, "unsellable", and set it to 1 on the inventory "iKey". Then I tried to sell the key, and it worked, it couldn't be sold and it showed me a message saying so. The poster sold like always. I could still buy keys, though. It would be simple to make an item unbuyable, too. With the reverse of this code, or simply by removing the items from the merchant's inventory, like you said (there are not many instances where this would be useful, though. Maybe to unlock some items as the player progresses, idk).

Code: ags
void on_mouse_click(MouseButton button) {
  if (!gShop.Visible) return;
  if (button != eMouseLeftInv) return;
  InventoryItem* ii = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  GUIControl* gc = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
  if (gc == null) return;
  InvWindow* iw = gc.AsInvWindow;
  if (iw == invShopPlayer && ii != null)
    if (ii.GetProperty("unsellable") != 0)
      Display("I can't possibly buy that!");
    else Sell(ii);
  if (iw == invShopMerchant && ii != null) Buy(ii);
}


I think I don't need anything else, it's a miracle 8-0 Thanks a lot, man! You're mighty helpful for a guy who probably has fantasies of shooting the monitor every now and then (laugh)

Egmundo Huevoz

Quote from: Khris on Mon 11/12/2017 02:23:06

(I don't know other ways to tag you)

Bro, sorry to bother you, but as I was progressing with my game, I noticed something. I can't grab, nor look at items in my inventory. Could you help me? Also, it doesn't show inventory quantities in the inventory, as it does in the shop.

Khris

The quantities are displayed using a GUI tailored to the shop. You can use the same mechanism for your regular inventory, but you have to actually implement it.

As for not being able to grab or look at inventory items, the shop uses custom inventory click handling (a setting in General Settings -> Inventory). This will of course disable AGS's default inv handling, so you need to implement it yourself.
Open the global script, go to the on_mouse_click in there, then add blocks for eMouseLeftInv (and eMouseRightInv) and implement click behavior. The item thas was clicked on can be determined using something like InventoryItem* clickedItem = inventory[game.inv_activated];

There are tons of existing threads about that topic, the forum search should hopefully turn something up.

Egmundo Huevoz

I managed to do it! I feel less of a noob now. (laugh) Thanks, Khris! As I read somewhere else before, I don't know what the forums would do without you.

Code: ags
function on_mouse_click(MouseButton button){
if (button == eMouseLeftInv){
  InventoryItem *i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
  if (mouse.Mode==eModeLookat)
    inventory[game.inv_activated].RunInteraction(mouse.Mode);
  else if ((i != null) && (mouse.Mode==eModeInteract)
    player.ActiveInventory = i;
  else if (mouse.Mode==eModeUseinv)
    inventory[game.inv_activated].RunInteraction(mouse.Mode);
  }
}

Egmundo Huevoz

I can't for the life of me adapt the quantities to the player's inv. I tried for hours and the farthest I got is to duplicate the quantities label inside the shop (in the position where it should be on the inventory window), but that's it. :(

SMF spam blocked by CleanTalk